Compare commits
48 Commits
i2p_0_6_1_
...
i2p_0_6_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7236d7d58 | ||
|
|
5182008b38 | ||
|
|
9d030327e6 | ||
|
|
a15c90d2cc | ||
|
|
84c2a713e1 | ||
|
|
7db9ce6e5b | ||
|
|
da42f5717b | ||
|
|
5241953e5d | ||
|
|
b1a5f61ba2 | ||
|
|
024a5a1ad4 | ||
|
|
b031de5404 | ||
|
|
dceac73951 | ||
|
|
8f95143488 | ||
|
|
a8f3043aae | ||
|
|
6c91b2d4a9 | ||
|
|
ddd438de35 | ||
|
|
16fd46db2b | ||
|
|
1159c155a4 | ||
|
|
30b4e2aa2a | ||
|
|
ae46fa2e6d | ||
|
|
9fc34895c9 | ||
|
|
08be4c7b3d | ||
|
|
7443457af4 | ||
|
|
979a4cfb69 | ||
|
|
ed285871bf | ||
|
|
8c70b8b32a | ||
|
|
14134694d7 | ||
|
|
807d2d3509 | ||
|
|
b222cd43f4 | ||
|
|
7f6aa327f2 | ||
|
|
49564a3878 | ||
|
|
12ddaff0ce | ||
|
|
a8ea239dcc | ||
|
|
ca391097a9 | ||
|
|
4297edc88f | ||
|
|
6de4673e9e | ||
|
|
f6979c811f | ||
|
|
bd86483204 | ||
|
|
53cf03cec6 | ||
|
|
e284a8878b | ||
|
|
14cd469c6d | ||
|
|
9050d7c218 | ||
|
|
0ad18cd0ba | ||
|
|
ca0af146b7 | ||
|
|
a2d2b031f4 | ||
|
|
2f36912ac0 | ||
|
|
53e32c8e64 | ||
|
|
10dde610dc |
@@ -267,10 +267,34 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
public InternalGZIPInputStream(InputStream in) throws IOException {
|
||||
super(in);
|
||||
}
|
||||
public long getTotalRead() { return super.inf.getTotalIn(); }
|
||||
public long getTotalExpanded() { return super.inf.getTotalOut(); }
|
||||
public long getRemaining() { return super.inf.getRemaining(); }
|
||||
public boolean getFinished() { return super.inf.finished(); }
|
||||
public long getTotalRead() {
|
||||
try {
|
||||
return super.inf.getTotalIn();
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public long getTotalExpanded() {
|
||||
try {
|
||||
return super.inf.getTotalOut();
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public long getRemaining() {
|
||||
try {
|
||||
return super.inf.getRemaining();
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public boolean getFinished() {
|
||||
try {
|
||||
return super.inf.finished();
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public String toString() {
|
||||
return "Read: " + getTotalRead() + " expanded: " + getTotalExpanded() + " remaining: " + getRemaining() + " finished: " + getFinished();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class I2PTunnelGUI extends Frame implements ActionListener, Logging {
|
||||
log.setEditable(false);
|
||||
log("enter 'help' for help.");
|
||||
pack();
|
||||
show();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
public void log(String s) {
|
||||
|
||||
@@ -490,7 +490,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
else if(ahelper != 0)
|
||||
str = FileUtil.readTextFile("docs/dnfb-header.ht", 100, true);
|
||||
else
|
||||
str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true);
|
||||
str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true);
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.net.SocketException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -223,15 +224,41 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
_gzipOut = new InternalGZIPOutputStream(out);
|
||||
out = _gzipOut;
|
||||
}
|
||||
public long getTotalRead() { return _gzipOut.getTotalRead(); }
|
||||
public long getTotalCompressed() { return _gzipOut.getTotalCompressed(); }
|
||||
public long getTotalRead() {
|
||||
InternalGZIPOutputStream gzipOut = _gzipOut;
|
||||
if (gzipOut != null)
|
||||
return gzipOut.getTotalRead();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
public long getTotalCompressed() {
|
||||
InternalGZIPOutputStream gzipOut = _gzipOut;
|
||||
if (gzipOut != null)
|
||||
return gzipOut.getTotalCompressed();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
private class InternalGZIPOutputStream extends GZIPOutputStream {
|
||||
public InternalGZIPOutputStream(OutputStream target) throws IOException {
|
||||
super(target);
|
||||
}
|
||||
public long getTotalRead() { return super.def.getTotalIn(); }
|
||||
public long getTotalCompressed() { return super.def.getTotalOut(); }
|
||||
public long getTotalRead() {
|
||||
try {
|
||||
return def.getTotalIn();
|
||||
} catch (Exception e) {
|
||||
// j2se 1.4.2_08 on linux is sometimes throwing an NPE in the getTotalIn() implementation
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public long getTotalCompressed() {
|
||||
try {
|
||||
return def.getTotalOut();
|
||||
} catch (Exception e) {
|
||||
// j2se 1.4.2_08 on linux is sometimes throwing an NPE in the getTotalOut() implementation
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String formatHeaders(Properties headers, StringBuffer command) {
|
||||
|
||||
@@ -139,23 +139,63 @@ public class EditBean extends IndexBean {
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunnelCount(int tunnel, int defaultCount) {
|
||||
public int getTunnelQuantity(int tunnel, int defaultQuantity) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String len = opts.getProperty("inbound.quantity");
|
||||
if (len == null) return defaultCount;
|
||||
if (len == null) return defaultQuantity;
|
||||
try {
|
||||
return Integer.parseInt(len);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultCount;
|
||||
return defaultQuantity;
|
||||
}
|
||||
} else {
|
||||
return defaultCount;
|
||||
return defaultQuantity;
|
||||
}
|
||||
} else {
|
||||
return defaultCount;
|
||||
return defaultQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunnelBackupQuantity(int tunnel, int defaultBackupQuantity) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String len = opts.getProperty("inbound.backupQuantity");
|
||||
if (len == null) return defaultBackupQuantity;
|
||||
try {
|
||||
return Integer.parseInt(len);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultBackupQuantity;
|
||||
}
|
||||
} else {
|
||||
return defaultBackupQuantity;
|
||||
}
|
||||
} else {
|
||||
return defaultBackupQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTunnelVariance(int tunnel, int defaultVariance) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = getOptions(tun);
|
||||
if (opts != null) {
|
||||
String len = opts.getProperty("inbound.lengthVariance");
|
||||
if (len == null) return defaultVariance;
|
||||
try {
|
||||
return Integer.parseInt(len);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultVariance;
|
||||
}
|
||||
} else {
|
||||
return defaultVariance;
|
||||
}
|
||||
} else {
|
||||
return defaultVariance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +227,10 @@ public class EditBean extends IndexBean {
|
||||
String val = opts.getProperty(key);
|
||||
if ("inbound.length".equals(key)) continue;
|
||||
if ("outbound.length".equals(key)) continue;
|
||||
if ("inbound.lengthVariance".equals(key)) continue;
|
||||
if ("outbound.lengthVariance".equals(key)) continue;
|
||||
if ("inbound.backupQuantity".equals(key)) continue;
|
||||
if ("outbound.backupQuantity".equals(key)) continue;
|
||||
if ("inbound.quantity".equals(key)) continue;
|
||||
if ("outbound.quantity".equals(key)) continue;
|
||||
if ("inbound.nickname".equals(key)) continue;
|
||||
@@ -224,4 +268,4 @@ public class EditBean extends IndexBean {
|
||||
}
|
||||
return props;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,9 @@ public class IndexBean {
|
||||
private String _i2cpHost;
|
||||
private String _i2cpPort;
|
||||
private String _tunnelDepth;
|
||||
private String _tunnelCount;
|
||||
private String _tunnelQuantity;
|
||||
private String _tunnelVariance;
|
||||
private String _tunnelBackupQuantity;
|
||||
private boolean _connectDelay;
|
||||
private String _customOptions;
|
||||
private String _proxyList;
|
||||
@@ -64,6 +66,10 @@ public class IndexBean {
|
||||
static final String PROP_NONCE = IndexBean.class.getName() + ".nonce";
|
||||
static final String CLIENT_NICKNAME = "shared clients";
|
||||
|
||||
public static final String PROP_THEME_NAME = "routerconsole.theme";
|
||||
public static final String PROP_CSS_DISABLED = "routerconsole.css.disabled";
|
||||
public static final String PROP_JS_DISABLED = "routerconsole.javascript.disabled";
|
||||
|
||||
public IndexBean() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(IndexBean.class);
|
||||
@@ -121,13 +127,13 @@ public class IndexBean {
|
||||
return "";
|
||||
if ( (_prevNonce != _curNonce) && (!validPassphrase(_passphrase)) )
|
||||
return "Invalid nonce, are you being spoofed?";
|
||||
if ("Stop all tunnels".equals(_action))
|
||||
if ("Stop all".equals(_action))
|
||||
return stopAll();
|
||||
else if ("Start all tunnels".equals(_action))
|
||||
else if ("Start all".equals(_action))
|
||||
return startAll();
|
||||
else if ("Restart all".equals(_action))
|
||||
return restartAll();
|
||||
else if ("Reload config".equals(_action))
|
||||
else if ("Reload configuration".equals(_action))
|
||||
return reloadConfig();
|
||||
else if ("stop".equals(_action))
|
||||
return stop();
|
||||
@@ -213,14 +219,22 @@ public class IndexBean {
|
||||
"client".equals(c.getType())
|
||||
) && "true".equalsIgnoreCase(c.getSharedClient())) {
|
||||
Properties cOpt = c.getConfig("");
|
||||
if (_tunnelCount != null) {
|
||||
cOpt.setProperty("option.inbound.quantity", _tunnelCount);
|
||||
cOpt.setProperty("option.outbound.quantity", _tunnelCount);
|
||||
if (_tunnelQuantity != null) {
|
||||
cOpt.setProperty("option.inbound.quantity", _tunnelQuantity);
|
||||
cOpt.setProperty("option.outbound.quantity", _tunnelQuantity);
|
||||
}
|
||||
if (_tunnelDepth != null) {
|
||||
cOpt.setProperty("option.inbound.length", _tunnelDepth);
|
||||
cOpt.setProperty("option.outbound.length", _tunnelDepth);
|
||||
}
|
||||
if (_tunnelVariance != null) {
|
||||
cOpt.setProperty("option.inbound.lengthVariance", _tunnelVariance);
|
||||
cOpt.setProperty("option.outbound.lengthVariance", _tunnelVariance);
|
||||
}
|
||||
if (_tunnelBackupQuantity != null) {
|
||||
cOpt.setProperty("option.inbound.backupQuantity", _tunnelBackupQuantity);
|
||||
cOpt.setProperty("option.outbound.backupQuantity", _tunnelBackupQuantity);
|
||||
}
|
||||
cOpt.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
|
||||
cOpt.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
|
||||
|
||||
@@ -275,6 +289,24 @@ public class IndexBean {
|
||||
// The remaining methods are simple bean props for the jsp to query
|
||||
////
|
||||
|
||||
public String getTheme() {
|
||||
String theme = _context.getProperty(PROP_THEME_NAME);
|
||||
if (theme != null)
|
||||
return "/themes/console/" + theme + "/";
|
||||
else
|
||||
return "/themes/console/";
|
||||
}
|
||||
|
||||
public boolean allowCSS() {
|
||||
String css = _context.getProperty(PROP_CSS_DISABLED);
|
||||
return (css == null);
|
||||
}
|
||||
|
||||
public boolean allowJS() {
|
||||
String js = _context.getProperty(PROP_JS_DISABLED);
|
||||
return (js == null);
|
||||
}
|
||||
|
||||
public int getTunnelCount() {
|
||||
if (_group == null) return 0;
|
||||
return _group.getControllers().size();
|
||||
@@ -313,10 +345,10 @@ public class IndexBean {
|
||||
}
|
||||
|
||||
public String getTypeName(String internalType) {
|
||||
if ("client".equals(internalType)) return "Client proxy";
|
||||
else if ("httpclient".equals(internalType)) return "HTTP proxy";
|
||||
else if ("ircclient".equals(internalType)) return "IRC proxy";
|
||||
else if ("server".equals(internalType)) return "Server";
|
||||
if ("client".equals(internalType)) return "Standard client";
|
||||
else if ("httpclient".equals(internalType)) return "HTTP client";
|
||||
else if ("ircclient".equals(internalType)) return "IRC client";
|
||||
else if ("server".equals(internalType)) return "Standard server";
|
||||
else if ("httpserver".equals(internalType)) return "HTTP server";
|
||||
else return internalType;
|
||||
}
|
||||
@@ -424,8 +456,16 @@ public class IndexBean {
|
||||
_tunnelDepth = (tunnelDepth != null ? tunnelDepth.trim() : null);
|
||||
}
|
||||
/** how many parallel inbound tunnels to use */
|
||||
public void setTunnelCount(String tunnelCount) {
|
||||
_tunnelCount = (tunnelCount != null ? tunnelCount.trim() : null);
|
||||
public void setTunnelQuantity(String tunnelQuantity) {
|
||||
_tunnelQuantity = (tunnelQuantity != null ? tunnelQuantity.trim() : null);
|
||||
}
|
||||
/** how much randomisation to apply to the depth of tunnels */
|
||||
public void setTunnelVariance(String tunnelVariance) {
|
||||
_tunnelVariance = (tunnelVariance != null ? tunnelVariance.trim() : null);
|
||||
}
|
||||
/** how many tunnels to hold in reserve to guard against failures */
|
||||
public void setTunnelBackupQuantity(String tunnelBackupQuantity) {
|
||||
_tunnelBackupQuantity = (tunnelBackupQuantity != null ? tunnelBackupQuantity.trim() : null);
|
||||
}
|
||||
/** what I2P session overrides should be used */
|
||||
public void setCustomOptions(String customOptions) {
|
||||
@@ -582,6 +622,7 @@ public class IndexBean {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -611,6 +652,10 @@ public class IndexBean {
|
||||
if ("outbound.length".equals(key)) continue;
|
||||
if ("inbound.quantity".equals(key)) continue;
|
||||
if ("outbound.quantity".equals(key)) continue;
|
||||
if ("inbound.lengthVariance".equals(key)) continue;
|
||||
if ("outbound.lengthVariance".equals(key)) continue;
|
||||
if ("inbound.backupQuantity".equals(key)) continue;
|
||||
if ("outbound.backupQuantity".equals(key)) continue;
|
||||
if ("inbound.nickname".equals(key)) continue;
|
||||
if ("outbound.nickname".equals(key)) continue;
|
||||
if ("i2p.streaming.connectDelay".equals(key)) continue;
|
||||
@@ -621,14 +666,22 @@ public class IndexBean {
|
||||
|
||||
config.setProperty("startOnLoad", _startOnLoad + "");
|
||||
|
||||
if (_tunnelCount != null) {
|
||||
config.setProperty("option.inbound.quantity", _tunnelCount);
|
||||
config.setProperty("option.outbound.quantity", _tunnelCount);
|
||||
if (_tunnelQuantity != null) {
|
||||
config.setProperty("option.inbound.quantity", _tunnelQuantity);
|
||||
config.setProperty("option.outbound.quantity", _tunnelQuantity);
|
||||
}
|
||||
if (_tunnelDepth != null) {
|
||||
config.setProperty("option.inbound.length", _tunnelDepth);
|
||||
config.setProperty("option.outbound.length", _tunnelDepth);
|
||||
}
|
||||
if (_tunnelVariance != null) {
|
||||
config.setProperty("option.inbound.lengthVariance", _tunnelVariance);
|
||||
config.setProperty("option.outbound.lengthVariance", _tunnelVariance);
|
||||
}
|
||||
if (_tunnelBackupQuantity != null) {
|
||||
config.setProperty("option.inbound.backupQuantity", _tunnelBackupQuantity);
|
||||
config.setProperty("option.outbound.backupQuantity", _tunnelBackupQuantity);
|
||||
}
|
||||
if (_connectDelay)
|
||||
config.setProperty("option.i2p.streaming.connectDelay", "1000");
|
||||
else
|
||||
@@ -673,4 +726,4 @@ public class IndexBean {
|
||||
buf.append((String)msgs.get(i)).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
if (tun != null) {
|
||||
try {
|
||||
int curTunnel = Integer.parseInt(tun);
|
||||
if (EditBean.staticIsClient(curTunnel)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else {
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
%>Invalid tunnel parameter<%
|
||||
}
|
||||
} else {
|
||||
String type = request.getParameter("type");
|
||||
int curTunnel = -1;
|
||||
if ("client".equals(type) || "httpclient".equals(type) || "ircclient".equals(type)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else if ("server".equals(type) || "httpserver".equals(type)) {
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %><%
|
||||
String tun = request.getParameter("tunnel");
|
||||
if (tun != null) {
|
||||
try {
|
||||
int curTunnel = Integer.parseInt(tun);
|
||||
if (EditBean.staticIsClient(curTunnel)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else {
|
||||
%>Invalid tunnel type<%
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
%>Invalid tunnel parameter<%
|
||||
}
|
||||
} else {
|
||||
String type = request.getParameter("type");
|
||||
int curTunnel = -1;
|
||||
if ("client".equals(type) || "httpclient".equals(type) || "ircclient".equals(type)) {
|
||||
%><jsp:include page="editClient.jsp" /><%
|
||||
} else if ("server".equals(type) || "httpserver".equals(type)) {
|
||||
%><jsp:include page="editServer.jsp" /><%
|
||||
} else {
|
||||
%>Invalid tunnel type<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
@@ -1,4 +1,5 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean"%><?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
int curTunnel = -1;
|
||||
@@ -10,284 +11,277 @@
|
||||
}
|
||||
}
|
||||
%>
|
||||
<html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
<title>I2PTunnel Webmanager - Edit</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
|
||||
|
||||
<% if (editBean.allowCSS()) {
|
||||
%><link href="images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
|
||||
<link href="<%=editBean.getTheme()%>default.css" rel="stylesheet" type="text/css" />
|
||||
<link href="<%=editBean.getTheme()%>i2ptunnel.css" rel="stylesheet" type="text/css" />
|
||||
<% }
|
||||
%>
|
||||
</head>
|
||||
<body>
|
||||
<form action="index.jsp">
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<table width="80%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<% if (curTunnel >= 0) { %>
|
||||
<b>Edit proxy settings</b>
|
||||
<% } else { %>
|
||||
<b>New proxy settings</b>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="30" maxlength="50" name="name" value="<%=editBean.getTunnelName(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Type: </b>
|
||||
<td><%
|
||||
if (curTunnel >= 0) {
|
||||
%><%=editBean.getTunnelType(curTunnel)%>
|
||||
<input type="hidden" name="type" value="<%=editBean.getInternalType(curTunnel)%>" />
|
||||
<%
|
||||
} else {
|
||||
%><%=editBean.getTypeName(request.getParameter("type"))%>
|
||||
<input type="hidden" name="type" value="<%=request.getParameter("type")%>" />
|
||||
<%
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Description: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="60" maxlength="80" name="description" value="<%=editBean.getTunnelDescription(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Start automatically?:</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.startAutomatically(curTunnel)) { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" checked="true" />
|
||||
<% } else { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" />
|
||||
<% } %>
|
||||
<i>(Check the Box for 'YES')</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <b>Listening Port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="6" maxlength="5" name="port" value="<%=editBean.getClientPort(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> Accessable by:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="reachableBy">
|
||||
<% String clientInterface = editBean.getClientInterface(curTunnel); %>
|
||||
<% if (("127.0.0.1".equals(clientInterface)) || (clientInterface == null) || (clientInterface.trim().length() <= 0)) { %>
|
||||
<option value="127.0.0.1" selected="true">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0">Everyone (0.0.0.0)</option>
|
||||
<option value="other">LAN Hosts (Please specify your LAN address)</option>
|
||||
<body id="tunnelEditPage">
|
||||
<div id="pageHeader">
|
||||
</div>
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachableByOther" size="20" />
|
||||
<% } else if ("0.0.0.0".equals(clientInterface)) { %>
|
||||
<option value="127.0.0.1">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0" selected="true">Everyone (0.0.0.0)</option>
|
||||
<option value="other">LAN Hosts (Please specify your LAN address)</option>
|
||||
<form method="post" action="index.jsp">
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachableByOther" size="20" />
|
||||
<% } else { %>
|
||||
<option value="127.0.0.1">Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0">Everyone (0.0.0.0)</option>
|
||||
<option value="other" selected="true">LAN Hosts (Please specify your LAN address)</option>
|
||||
<div id="tunnelEditPanel" class="panel">
|
||||
<div class="header">
|
||||
<%
|
||||
String tunnelTypeName = "";
|
||||
String tunnelType = "";
|
||||
if (curTunnel >= 0) {
|
||||
tunnelTypeName = editBean.getTunnelType(curTunnel);
|
||||
tunnelType = editBean.getInternalType(curTunnel);
|
||||
%><h4>Edit proxy settings</h4><%
|
||||
} else {
|
||||
tunnelTypeName = editBean.getTypeName(request.getParameter("type"));
|
||||
tunnelType = request.getParameter("type");
|
||||
%><h4>New proxy settings</h4><%
|
||||
} %>
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
</select>
|
||||
|
||||
<b>others:</b>
|
||||
<input type="text" name="reachableByOther" size="20" value="<%=clientInterface%>" />
|
||||
<% } %>
|
||||
<div id="nameField" class="rowItem">
|
||||
<label for="name" accesskey="N">
|
||||
<span class="accessKey">N</span>ame:
|
||||
</label>
|
||||
<input type="text" size="30" maxlength="50" name="name" id="name" title="Tunnel Name" value="<%=editBean.getTunnelName(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="typeField" class="rowItem">
|
||||
<label>Type:</label>
|
||||
<span class="text"><%=tunnelTypeName%></span>
|
||||
</div>
|
||||
<div id="descriptionField" class="rowItem">
|
||||
<label for="description" accesskey="e">
|
||||
D<span class="accessKey">e</span>scription:
|
||||
</label>
|
||||
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="accessField" class="rowItem">
|
||||
<label>Access Point:</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="port" accesskey="P">
|
||||
<span class="accessKey">P</span>ort:
|
||||
</label>
|
||||
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="reachField" class="rowItem">
|
||||
<label for="reachableBy" accesskey="r">
|
||||
<span class="accessKey">R</span>eachable by:
|
||||
</label>
|
||||
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox">
|
||||
<% String clientInterface = editBean.getClientInterface(curTunnel);
|
||||
String otherInterface = "";
|
||||
if (!("127.0.0.1".equals(clientInterface)) &&
|
||||
!("0.0.0.0".equals(clientInterface)) &&
|
||||
(clientInterface != null) &&
|
||||
(clientInterface.trim().length() > 0)) {
|
||||
otherInterface = clientInterface;
|
||||
}
|
||||
%><option value="127.0.0.1"<%=("127.0.0.1".equals(clientInterface) ? " selected=\"selected\"" : "")%>>Locally (127.0.0.1)</option>
|
||||
<option value="0.0.0.0"<%=("0.0.0.0".equals(clientInterface) ? " selected=\"selected\"" : "")%>>Everyone (0.0.0.0)</option>
|
||||
<option value="other"<%=(!("".equals(otherInterface)) ? " selected=\"selected\"" : "")%>>LAN Hosts (Please specify your LAN address)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="otherField" class="rowItem">
|
||||
<label for="reachableByOther" accesskey="O">
|
||||
<span class="accessKey">O</span>ther:
|
||||
</label>
|
||||
<input type="text" size="20" id="reachableByOther" name="reachableByOther" title="Alternative IP for Client Access" value="<%=otherInterface%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<% if ("httpclient".equals(editBean.getInternalType(curTunnel))) {
|
||||
%><div id="destinationField" class="rowItem">
|
||||
<label for="proxyList" accesskey="x">
|
||||
Outpro<span class="accessKey">x</span>ies:
|
||||
</label>
|
||||
<input type="text" size="30" id="proxyList" name="proxyList" title="List of Outproxy I2P destinations" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% } else {
|
||||
%><div id="destinationField" class="rowItem">
|
||||
<label for="targetDestination" accesskey="T">
|
||||
<span class="accessKey">T</span>unnel Destination:
|
||||
</label>
|
||||
<input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext" />
|
||||
<span class="comment">(name or destination)</span>
|
||||
</div>
|
||||
<% }
|
||||
%><div id="profileField" class="rowItem">
|
||||
<label for="profile" accesskey="f">
|
||||
Pro<span class="accessKey">f</span>ile:
|
||||
</label>
|
||||
<select id="profile" name="profile" title="Connection Profile" class="selectbox">
|
||||
<% boolean interactiveProfile = editBean.isInteractive(curTunnel);
|
||||
%><option <%=(interactiveProfile == true ? "selected=\"selected\" " : "")%>value="interactive">interactive connection </option>
|
||||
<option <%=(interactiveProfile == false ? "selected=\"selected\" " : "")%>value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="delayConnectField" class="rowItem">
|
||||
<label for="connectDelay" accesskey="y">
|
||||
Dela<span class="accessKey">y</span> Connect:
|
||||
</label>
|
||||
<input value="1000" type="checkbox" id="connectDelay" name="connectDelay" title="Delay Connection"<%=(editBean.shouldDelay(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<span class="comment">(for request/response connections)</span>
|
||||
</div>
|
||||
<div id="sharedtField" class="rowItem">
|
||||
<label for="shared" accesskey="h">
|
||||
S<span class="accessKey">h</span>ared Client:
|
||||
</label>
|
||||
<input value="true" type="checkbox" id="shared" name="shared" title="Share tunnels with other clients"<%=(editBean.isSharedClient(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<span class="comment">(Share tunnels with other clients and irc/httpclients? Change requires restart of client proxy)</span>
|
||||
</div>
|
||||
<div id="startupField" class="rowItem">
|
||||
<label for="startOnLoad" accesskey="a">
|
||||
<span class="accessKey">A</span>uto Start:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="startOnLoad" title="Start Tunnel Automatically"<%=(editBean.startAutomatically(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<span class="comment">(Check the Box for 'YES')</span>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<% if ("httpclient".equals(editBean.getInternalType(curTunnel))) { %>
|
||||
<td><b>Outproxies:</b>
|
||||
<% } else { %>
|
||||
<td><b>Target:</b>
|
||||
<% } %>
|
||||
</td>
|
||||
<td>
|
||||
<% if ("httpclient".equals(editBean.getInternalType(curTunnel))) { %>
|
||||
<input type="text" name="proxyList" value="<%=editBean.getClientDestination(curTunnel)%>" />
|
||||
<% } else { %>
|
||||
<input type="text" name="targetDestination" value="<%=editBean.getClientDestination(curTunnel)%>" />
|
||||
<% } %>
|
||||
<i>(name or destination)</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Delayed connect?</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.shouldDelay(curTunnel)) { %>
|
||||
<input type="checkbox" value="1000" name="connectDelay" checked="true" />
|
||||
<% } else { %>
|
||||
<input type="checkbox" value="1000" name="connectDelay" />
|
||||
<% } %>
|
||||
<i>(for request/response connections)</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Profile:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="profile">
|
||||
<% if (editBean.isInteractive(curTunnel)) { %>
|
||||
<option value="interactive" selected="true">interactive connection </option>
|
||||
<option value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
<% } else { %>
|
||||
<option value="interactive">interactive connection </option>
|
||||
<option value="bulk" selected="true">bulk connection (downloads/websites/BT) </option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Shared Client</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.isSharedClient(curTunnel)) { %>
|
||||
<input type="checkbox" value="true" name="shared" checked="true" />
|
||||
<% } else { %>
|
||||
<input type="checkbox" value="true" name="shared" />
|
||||
<% } %>
|
||||
<i>(Share tunnels with other clients and irc/httpclients? Change requires restart of client proxy)</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<b><hr size="1">
|
||||
Advanced networking options<br />
|
||||
<span style="color:#dd0000;">(NOTE: when this client proxy is configured to share tunnels, then these options are for all the shared proxy clients!)</span></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Tunnel depth:</b>
|
||||
</td>
|
||||
<td><select name="tunnelDepth">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
switch (tunnelDepth) {
|
||||
case 0: %>
|
||||
<option value="0" selected="true">0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 1: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" selected="true">1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" selected="true">2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> hop tunnel</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Tunnel count:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="tunnelCount">
|
||||
<% int tunnelCount = editBean.getTunnelCount(curTunnel, 2);
|
||||
switch (tunnelCount) {
|
||||
case 1: %>
|
||||
<option value="1" selected="true" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" selected="true" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 3: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" selected="true" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> inbound tunnels</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
<tr>
|
||||
<td><b>I2CP host:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientHost" size="20" value="<%=editBean.getI2CPHost(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>I2CP port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientPort" size="20" value="<%=editBean.getI2CPPort(curTunnel)%>" /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Custom options:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="customOptions" size="60" value="<%=editBean.getCustomOptions(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<hr size="1">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Save:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Save changes" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Delete?</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Delete this proxy" />
|
||||
<b><span style="color:#dd0000;">confirm delete:</span></b>
|
||||
<input type="checkbox" value="true" name="removeConfirm" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<div id="tunnelAdvancedNetworking" class="panel">
|
||||
<div class="header">
|
||||
<h4>Advanced networking options</h4>
|
||||
<span class="comment">(NOTE: when this client proxy is configured to share tunnels, then these options are for all the shared proxy clients!)</span>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="tunnelOptionsField" class="rowItem">
|
||||
<label>Tunnel Options:</label>
|
||||
</div>
|
||||
<div id="depthField" class="rowItem">
|
||||
<label for="tunnelDepth" accesskey="t">
|
||||
Dep<span class="accessKey">t</span>h:
|
||||
</label>
|
||||
<select id="tunnelDepth" name="tunnelDepth" title="Depth of each Tunnel" class="selectbox">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% if (tunnelDepth > 2) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="varianceField" class="rowItem">
|
||||
<label for="tunnelVariance" accesskey="v">
|
||||
<span class="accessKey">V</span>ariance:
|
||||
</label>
|
||||
<select id="tunnelVariance" name="tunnelVariance" title="Level of Randomization for Tunnel Depth" class="selectbox">
|
||||
<% int tunnelVariance = editBean.getTunnelVariance(curTunnel, -1);
|
||||
%><option value="0"<%=(tunnelVariance == 0 ? " selected=\"selected\"" : "") %>>0 hop variance (no randomisation, consistant performance)</option>
|
||||
<option value="-1"<%=(tunnelVariance == -1 ? " selected=\"selected\"" : "") %>>+/- 0-1 hop variance (standard randomisation, standard performance)</option>
|
||||
<option value="-2"<%=(tunnelVariance == -2 ? " selected=\"selected\"" : "") %>>+/- 0-2 hop variance (high randomisation, variable performance)</option>
|
||||
<option value="1"<%=(tunnelVariance == 1 ? " selected=\"selected\"" : "") %>>+ 0-1 hop variance (medium additive randomisation, subtractive performance)</option>
|
||||
<option value="2"<%=(tunnelVariance == 2 ? " selected=\"selected\"" : "") %>>+ 0-2 hop variance (high additive randomisation, subtractive performance)</option>
|
||||
<% if (tunnelVariance > 2 || tunnelVariance < -2) {
|
||||
%> <option value="<%=tunnelVariance%>" selected="selected"><%= (tunnelVariance > 2 ? "+ " : "+/- ") %>0-<%=tunnelVariance%> hop variance</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="countField" class="rowItem">
|
||||
<label for="tunnelQuantity" accesskey="C">
|
||||
<span class="accessKey">C</span>ount:
|
||||
</label>
|
||||
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
|
||||
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% if (tunnelQuantity > 3) {
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="backupField" class="rowItem">
|
||||
<label for="tunnelBackupQuantity" accesskey="b">
|
||||
<span class="accessKey">B</span>ackup Count:
|
||||
</label>
|
||||
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
|
||||
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
|
||||
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
|
||||
<% if (tunnelBackupQuantity > 3) {
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label>I2CP Options:</label>
|
||||
</div>
|
||||
<div id="optionsHostField" class="rowItem">
|
||||
<label for="clientHost" accesskey="o">
|
||||
H<span class="accessKey">o</span>st:
|
||||
</label>
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="optionsPortField" class="rowItem">
|
||||
<label for="clientPort" accesskey="r">
|
||||
Po<span class="accessKey">r</span>t:
|
||||
</label>
|
||||
<input type="text" id="clientPort" name="clientPort" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="customOptionsField" class="rowItem">
|
||||
<label for="customOptions" accesskey="u">
|
||||
C<span class="accessKey">u</span>stom options:
|
||||
</label>
|
||||
<input type="text" id="customOptions" name="customOptions" size="60" title="Custom Options" value="<%=editBean.getCustomOptions(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
<div id="globalOperationsPanel" class="panel">
|
||||
<div class="header"></div>
|
||||
<div class="footer">
|
||||
<div class="toolbox">
|
||||
<input type="hidden" value="true" name="removeConfirm" />
|
||||
<button id="controlSave" accesskey="S" class="control" type="submit" name="action" value="Save changes" title="Save Changes"><span class="accessKey">S</span>ave</button><button id="controlDelete" <%=(editBean.allowJS() ? "onclick=\"if (!confirm('Are you sure you want to delete?')) { return false; }\" " : "")%>accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><span class="accessKey">D</span>elete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="pageFooter">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,5 @@
|
||||
<%@page contentType="text/html" %>
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean"%><?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
|
||||
<% String tun = request.getParameter("tunnel");
|
||||
int curTunnel = -1;
|
||||
@@ -10,224 +11,249 @@
|
||||
}
|
||||
}
|
||||
%>
|
||||
<html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
<title>I2PTunnel Webmanager - Edit</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
|
||||
|
||||
<% if (editBean.allowCSS()) {
|
||||
%><link href="images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
|
||||
<link href="<%=editBean.getTheme()%>default.css" rel="stylesheet" type="text/css" />
|
||||
<link href="<%=editBean.getTheme()%>i2ptunnel.css" rel="stylesheet" type="text/css" />
|
||||
<% }
|
||||
%>
|
||||
</head>
|
||||
<body>
|
||||
<form action="index.jsp">
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<table width="80%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<% if (curTunnel >= 0) { %>
|
||||
<b>Edit server settings</b>
|
||||
<% } else { %>
|
||||
<b>New server settings</b>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="30" maxlength="50" name="name" value="<%=editBean.getTunnelName(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Type: </b>
|
||||
<td><%
|
||||
if (curTunnel >= 0) {
|
||||
%><%=editBean.getTunnelType(curTunnel)%>
|
||||
<input type="hidden" name="type" value="<%=editBean.getInternalType(curTunnel)%>" />
|
||||
<%
|
||||
} else {
|
||||
%><%=editBean.getTypeName(request.getParameter("type"))%>
|
||||
<input type="hidden" name="type" value="<%=request.getParameter("type")%>" />
|
||||
<%
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Description: </b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" size="60" maxlength="80" name="description" value="<%=editBean.getTunnelDescription(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Start automatically?:</b>
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.startAutomatically(curTunnel)) { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" checked="true" />
|
||||
<% } else { %>
|
||||
<input value="1" type="checkbox" name="startOnLoad" />
|
||||
<% } %>
|
||||
<i>(Check the Box for 'YES')</i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <b>Target:</b>
|
||||
</td>
|
||||
<td>
|
||||
Host: <input type="text" size="20" name="targetHost" value="<%=editBean.getTargetHost(curTunnel)%>" />
|
||||
Port: <input type="text" size="6" maxlength="5" name="targetPort" value="<%=editBean.getTargetPort(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<% String curType = editBean.getInternalType(curTunnel);
|
||||
if ( (curType == null) || (curType.trim().length() <= 0) )
|
||||
curType = request.getParameter("type");
|
||||
if ("httpserver".equals(curType)) { %>
|
||||
<tr>
|
||||
<td><b>Website name:</b></td>
|
||||
<td><input type="text" size="20" name="spoofedHost" value="<%=editBean.getSpoofedHost(curTunnel)%>" />
|
||||
</td></tr>
|
||||
<% } %>
|
||||
<tr>
|
||||
<td><b>Private key file:</b>
|
||||
</td>
|
||||
<td><input type="text" size="30" name="privKeyFile" value="<%=editBean.getPrivateKeyFile(curTunnel)%>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Profile:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="profile">
|
||||
<% if (editBean.isInteractive(curTunnel)) { %>
|
||||
<option value="interactive" selected="true">interactive connection </option>
|
||||
<option value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
<% } else { %>
|
||||
<option value="interactive">interactive connection </option>
|
||||
<option value="bulk" selected="true">bulk connection (downloads/websites/BT) </option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" align="left"><b>Local destination:</b><br /><i>(if known)</i></td>
|
||||
<td valign="top" align="left"><input type="text" size="60" value="<%=editBean.getDestinationBase64(curTunnel)%>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<b><hr size="1">
|
||||
Advanced networking options<br />
|
||||
</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Tunnel depth:</b>
|
||||
</td>
|
||||
<td><select name="tunnelDepth">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
switch (tunnelDepth) {
|
||||
case 0: %>
|
||||
<option value="0" selected="true">0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 1: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" selected="true">1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" selected="true">2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="0" >0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1" >1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2" >2 hop tunnel (high anonymity, high latency)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> hop tunnel</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Tunnel count:</b>
|
||||
</td>
|
||||
<td>
|
||||
<select name="tunnelCount">
|
||||
<% int tunnelCount = editBean.getTunnelCount(curTunnel, 2);
|
||||
switch (tunnelCount) {
|
||||
case 1: %>
|
||||
<option value="1" selected="true" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 2: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" selected="true" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
case 3: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" selected="true" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% break;
|
||||
default: %>
|
||||
<option value="1" >1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2" >2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3" >3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<option value="<%=tunnelDepth%>" ><%=tunnelDepth%> inbound tunnels</option>
|
||||
<% } %>
|
||||
</select>
|
||||
</td>
|
||||
<tr>
|
||||
<td><b>I2CP host:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientHost" size="20" value="<%=editBean.getI2CPHost(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>I2CP port:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="clientPort" size="20" value="<%=editBean.getI2CPPort(curTunnel)%>" /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Custom options:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="customOptions" size="60" value="<%=editBean.getCustomOptions(curTunnel)%>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<hr size="1">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Save:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Save changes" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Delete?</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" name="action" value="Delete this proxy" />
|
||||
<b><span style="color:#dd0000;">confirm delete:</span></b>
|
||||
<input type="checkbox" value="true" name="removeConfirm" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<body id="tunnelEditPage">
|
||||
<div id="pageHeader">
|
||||
</div>
|
||||
|
||||
<form method="post" action="index.jsp">
|
||||
|
||||
<div id="tunnelEditPanel" class="panel">
|
||||
<div class="header">
|
||||
<%
|
||||
String tunnelTypeName = "";
|
||||
String tunnelType = "";
|
||||
if (curTunnel >= 0) {
|
||||
tunnelTypeName = editBean.getTunnelType(curTunnel);
|
||||
tunnelType = editBean.getInternalType(curTunnel);
|
||||
%><h4>Edit server settings</h4><%
|
||||
} else {
|
||||
tunnelTypeName = editBean.getTypeName(request.getParameter("type"));
|
||||
tunnelType = request.getParameter("type");
|
||||
%><h4>New server settings</h4><%
|
||||
} %>
|
||||
<input type="hidden" name="tunnel" value="<%=request.getParameter("tunnel")%>" />
|
||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="nameField" class="rowItem">
|
||||
<label for="name" accesskey="N">
|
||||
<span class="accessKey">N</span>ame:
|
||||
</label>
|
||||
<input type="text" size="30" maxlength="50" name="name" id="name" title="Tunnel Name" value="<%=editBean.getTunnelName(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="typeField" class="rowItem">
|
||||
<label>Type:</label>
|
||||
<span class="text"><%=tunnelTypeName%></span>
|
||||
</div>
|
||||
<div id="descriptionField" class="rowItem">
|
||||
<label for="description" accesskey="e">
|
||||
D<span class="accessKey">e</span>scription:
|
||||
</label>
|
||||
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="startupField" class="rowItem">
|
||||
<label for="startOnLoad" accesskey="a">
|
||||
<span class="accessKey">A</span>uto Start:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="startOnLoad" title="Start Tunnel Automatically"<%=(editBean.startAutomatically(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<span class="comment">(Check the Box for 'YES')</span>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="targetField" class="rowItem">
|
||||
<label>Target:</label>
|
||||
</div>
|
||||
<div id="hostField" class="rowItem">
|
||||
<label for="targetHost" accesskey="H">
|
||||
<span class="accessKey">H</span>ost:
|
||||
</label>
|
||||
<input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=editBean.getTargetHost(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="targetPort" accesskey="P">
|
||||
<span class="accessKey">P</span>ort:
|
||||
</label>
|
||||
<input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="Target Port Number" value="<%=editBean.getTargetPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<% if ("httpserver".equals(tunnelType)) {
|
||||
%><div id="websiteField" class="rowItem">
|
||||
<label for="spoofedHost" accesskey="W">
|
||||
<span class="accessKey">W</span>ebsite name:
|
||||
</label>
|
||||
<input type="text" size="20" id="spoofedHost" name="spoofedHost" title="Website Host Name" value="<%=editBean.getSpoofedHost(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% }
|
||||
%><div id="privKeyField" class="rowItem">
|
||||
<label for="privKeyFile" accesskey="k">
|
||||
Private <span class="accessKey">k</span>ey file:
|
||||
</label>
|
||||
<input type="text" size="30" id="privKeyFile" name="privKeyFile" title="Path to Private Key File" value="<%=editBean.getPrivateKeyFile(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="profileField" class="rowItem">
|
||||
<label for="profile" accesskey="f">
|
||||
Pro<span class="accessKey">f</span>ile:
|
||||
</label>
|
||||
<select id="profile" name="profile" title="Connection Profile" class="selectbox">
|
||||
<% boolean interactiveProfile = editBean.isInteractive(curTunnel);
|
||||
%><option <%=(interactiveProfile == true ? "selected=\"selected\" " : "")%>value="interactive">interactive connection </option>
|
||||
<option <%=(interactiveProfile == false ? "selected=\"selected\" " : "")%>value="bulk">bulk connection (downloads/websites/BT) </option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="destinationField" class="rowItem">
|
||||
<label for="localDestination" accesskey="L">
|
||||
<span class="accessKey">L</span>ocal destination:
|
||||
</label>
|
||||
<input type="text" size="60" readonly="readonly" id="localDestination" title="Read Only: Local Destination (if known)" value="<%=editBean.getDestinationBase64(curTunnel)%>" class="freetext" />
|
||||
<span class="comment">(if known)</span>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tunnelAdvancedNetworking" class="panel">
|
||||
<div class="header">
|
||||
<h4>Advanced networking options</h4>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="tunnelOptionsField" class="rowItem">
|
||||
<label>Tunnel Options:</label>
|
||||
</div>
|
||||
<div id="depthField" class="rowItem">
|
||||
<label for="tunnelDepth" accesskey="t">
|
||||
Dep<span class="accessKey">t</span>h:
|
||||
</label>
|
||||
<select id="tunnelDepth" name="tunnelDepth" title="Depth of each Tunnel" class="selectbox">
|
||||
<% int tunnelDepth = editBean.getTunnelDepth(curTunnel, 2);
|
||||
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
|
||||
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
|
||||
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
|
||||
<% if (tunnelDepth > 2) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="varianceField" class="rowItem">
|
||||
<label for="tunnelVariance" accesskey="v">
|
||||
<span class="accessKey">V</span>ariance:
|
||||
</label>
|
||||
<select id="tunnelVariance" name="tunnelVariance" title="Level of Randomization for Tunnel Depth" class="selectbox">
|
||||
<% int tunnelVariance = editBean.getTunnelVariance(curTunnel, -1);
|
||||
%><option value="0"<%=(tunnelVariance == 0 ? " selected=\"selected\"" : "") %>>0 hop variance (no randomisation, consistant performance)</option>
|
||||
<option value="-1"<%=(tunnelVariance == -1 ? " selected=\"selected\"" : "") %>>+/- 0-1 hop variance (standard randomisation, standard performance)</option>
|
||||
<option value="-2"<%=(tunnelVariance == -2 ? " selected=\"selected\"" : "") %>>+/- 0-2 hop variance (high randomisation, variable performance)</option>
|
||||
<option value="1"<%=(tunnelVariance == 1 ? " selected=\"selected\"" : "") %>>+ 0-1 hop variance (medium additive randomisation, subtractive performance)</option>
|
||||
<option value="2"<%=(tunnelVariance == 2 ? " selected=\"selected\"" : "") %>>+ 0-2 hop variance (high additive randomisation, subtractive performance)</option>
|
||||
<% if (tunnelVariance > 2 || tunnelVariance < -2) {
|
||||
%> <option value="<%=tunnelVariance%>" selected="selected"><%= (tunnelVariance > 2 ? "+ " : "+/- ") %>0-<%=tunnelVariance%> hop variance</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="countField" class="rowItem">
|
||||
<label for="tunnelQuantity" accesskey="C">
|
||||
<span class="accessKey">C</span>ount:
|
||||
</label>
|
||||
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
|
||||
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
|
||||
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
|
||||
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
|
||||
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
|
||||
<% if (tunnelQuantity > 3) {
|
||||
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
<div id="backupField" class="rowItem">
|
||||
<label for="tunnelBackupQuantity" accesskey="b">
|
||||
<span class="accessKey">B</span>ackup Count:
|
||||
</label>
|
||||
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
|
||||
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
|
||||
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
|
||||
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
|
||||
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
|
||||
<% if (tunnelBackupQuantity > 3) {
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
|
||||
<% }
|
||||
%></select>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label>I2CP Options:</label>
|
||||
</div>
|
||||
<div id="optionsHostField" class="rowItem">
|
||||
<label for="clientHost" accesskey="o">
|
||||
H<span class="accessKey">o</span>st:
|
||||
</label>
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="optionsPortField" class="rowItem">
|
||||
<label for="clientPort" accesskey="r">
|
||||
Po<span class="accessKey">r</span>t:
|
||||
</label>
|
||||
<input type="text" id="clientPort" name="clientPort" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="customOptionsField" class="rowItem">
|
||||
<label for="customOptions" accesskey="u">
|
||||
C<span class="accessKey">u</span>stom options:
|
||||
</label>
|
||||
<input type="text" id="customOptions" name="customOptions" size="60" title="Custom Options" value="<%=editBean.getCustomOptions(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
<div id="globalOperationsPanel" class="panel">
|
||||
<div class="header"></div>
|
||||
<div class="footer">
|
||||
<div class="toolbox">
|
||||
<input type="hidden" value="true" name="removeConfirm" />
|
||||
<button id="controlSave" accesskey="S" class="control" type="submit" name="action" value="Save changes" title="Save Changes"><span class="accessKey">S</span>ave</button><button id="controlDelete" <%=(editBean.allowJS() ? "onclick=\"if (!confirm('Are you sure you want to delete?')) { return false; }\" " : "")%>accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><span class="accessKey">D</span>elete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="pageFooter">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,185 +1,259 @@
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.IndexBean" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<%@page contentType="text/html" import="net.i2p.i2ptunnel.web.IndexBean"%><?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<jsp:useBean class="net.i2p.i2ptunnel.web.IndexBean" id="indexBean" scope="request" />
|
||||
<jsp:setProperty name="indexBean" property="*" />
|
||||
|
||||
<html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>I2PTunnel Webmanager</title>
|
||||
<title>I2PTunnel Webmanager - List</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
|
||||
|
||||
<% if (indexBean.allowCSS()) {
|
||||
%><link href="images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
|
||||
<link href="<%=indexBean.getTheme()%>default.css" rel="stylesheet" type="text/css" />
|
||||
<link href="<%=indexBean.getTheme()%>i2ptunnel.css" rel="stylesheet" type="text/css" />
|
||||
<% }
|
||||
%>
|
||||
</head>
|
||||
<body style="font-family: Verdana, Tahoma, Helvetica, sans-serif;font-size:12px;">
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td nowrap="true"><b>New Messages: </b><br />
|
||||
<a href="index.jsp">refresh</a>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="3" cols="60" readonly="true"><jsp:getProperty name="indexBean" property="messages" /></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<body id="tunnelListPage">
|
||||
<div id="pageHeader">
|
||||
</div>
|
||||
|
||||
<div id="statusMessagePanel" class="panel">
|
||||
<div class="header">
|
||||
<h4>Status Messages</h4>
|
||||
</div>
|
||||
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="7" align="center" valign="middle" style="font-size:14px;">
|
||||
<b>Your Client Tunnels:</b><br />
|
||||
<hr size="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="15%"><b>Name:</b></td>
|
||||
<td><b>Port:</b></td>
|
||||
<td><b>Type:</b></td>
|
||||
<td><b>Interface:</b></td>
|
||||
<td><b>Status:</b></td>
|
||||
</tr>
|
||||
<% for (int curClient = 0; curClient < indexBean.getTunnelCount(); curClient++) {
|
||||
if (!indexBean.isClient(curClient)) continue; %>
|
||||
<tr>
|
||||
<td valign="top" align="left">
|
||||
<b><a href="edit.jsp?tunnel=<%=curClient%>"><%=indexBean.getTunnelName(curClient) %></a></b></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getClientPort(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getTunnelType(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%=indexBean.getClientInterface(curClient) %></td>
|
||||
<td valign="top" align="left" nowrap="true"><%
|
||||
switch (indexBean.getTunnelStatus(curClient)) {
|
||||
case IndexBean.STARTING:
|
||||
%><b><span style="color:#339933">Starting...</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">[STOP]</a><%
|
||||
break;
|
||||
case IndexBean.RUNNING:
|
||||
%><b><span style="color:#00dd00">Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">[STOP]</a><%
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><b><span style="color:#dd0000">Not Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curClient%>">[START]</a><%
|
||||
break;
|
||||
}
|
||||
%></td>
|
||||
</tr>
|
||||
<tr><td align="right" valign="top">Destination:</td>
|
||||
<td colspan="4"><input align="left" size="40" valign="top" style="overflow: hidden" readonly="true" value="<%=indexBean.getClientDestination(curClient) %>" /></td></tr>
|
||||
<tr>
|
||||
<td valign="top" align="right">Description:</td>
|
||||
<td valign="top" align="left" colspan="4"><%=indexBean.getTunnelDescription(curClient) %></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="5" align="center" valign="middle" style="font-size:14px;">
|
||||
<b>Your Server Tunnels:</b><br />
|
||||
<hr size="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="15%"><b>Name: </b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Points at:</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Status:</b>
|
||||
</td>
|
||||
</tr>
|
||||
<textarea id="statusMessages" rows="3" cols="60" readonly="readonly"><jsp:getProperty name="indexBean" property="messages" /></textarea>
|
||||
|
||||
<% for (int curServer = 0; curServer < indexBean.getTunnelCount(); curServer++) {
|
||||
if (indexBean.isClient(curServer)) continue; %>
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<b><a href="edit.jsp?tunnel=<%=curServer%>"><%=indexBean.getTunnelName(curServer)%></a></b>
|
||||
</td>
|
||||
<td valign="top"><%=indexBean.getServerTarget(curServer)%></td>
|
||||
<td valign="top" nowrap="true"><%
|
||||
switch (indexBean.getTunnelStatus(curServer)) {
|
||||
case IndexBean.RUNNING:
|
||||
%><b><span style="color:#00dd00">Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">[STOP]</a><%
|
||||
if ("httpserver".equals(indexBean.getInternalType(curServer))) {
|
||||
%> (<a href="http://<%=(new java.util.Random()).nextLong()%>.i2p/?i2paddresshelper=<%=indexBean.getDestinationBase64(curServer)%>">preview</a>)<%
|
||||
}
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><b><span style="color:#dd0000">Not Running</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curServer%>">[START]</a><%
|
||||
break;
|
||||
case IndexBean.STARTING:
|
||||
%>
|
||||
<b><span style="color:#339933">Starting...</span></b>
|
||||
<a href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">[STOP]</a><%
|
||||
break;
|
||||
}
|
||||
%>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td valign="top" align="right">Description:</td>
|
||||
<td valign="top" align="left" colspan="2"><%=indexBean.getTunnelDescription(curServer)%></td></tr>
|
||||
<% } %>
|
||||
<div class="footer">
|
||||
<div class="toolbox">
|
||||
<a class="control" href="index.jsp">Refresh</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table width="90%" align="center" border="0" cellpadding="1" cellspacing="1">
|
||||
<tr>
|
||||
<td style="background-color:#000">
|
||||
<div style="background-color:#ffffed">
|
||||
<table width="100%" align="center" border="0" cellpadding="4" cellspacing="1">
|
||||
<tr>
|
||||
<td colspan="2" align="center" valign="middle">
|
||||
<b>Operations Menu - Please chose from below!</b><br /><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<form action="index.jsp" method="GET">
|
||||
<td >
|
||||
<input type="hidden" name="nonce" value="<%=indexBean.getNextNonce()%>" />
|
||||
<input type="submit" name="action" value="Stop all tunnels" />
|
||||
<input type="submit" name="action" value="Start all tunnels" />
|
||||
<input type="submit" name="action" value="Restart all" />
|
||||
<input type="submit" name="action" value="Reload config" />
|
||||
</td>
|
||||
</form>
|
||||
<form action="edit.jsp">
|
||||
<td >
|
||||
<b>Add new:</b>
|
||||
<select name="type">
|
||||
<option value="httpclient">HTTP proxy</option>
|
||||
<option value="ircclient">IRC proxy</option>
|
||||
<option value="client">Client tunnel</option>
|
||||
<option value="server">Server tunnel</option>
|
||||
<option value="httpserver">HTTP server tunnel</option>
|
||||
</select> <input type="submit" value="Create" />
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="localClientTunnelList" class="panel">
|
||||
<div class="header">
|
||||
<h4>Local Client Tunnels</h4>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div class="nameHeaderField rowItem">
|
||||
<label>Name:</label>
|
||||
</div>
|
||||
<div class="portHeaderField rowItem">
|
||||
<label>Port:</label>
|
||||
</div>
|
||||
<div class="typeHeaderField rowItem">
|
||||
<label>Type:</label>
|
||||
</div>
|
||||
<div class="interfaceHeaderField rowItem">
|
||||
<label>Interface:</label>
|
||||
</div>
|
||||
<div class="statusHeaderField rowItem">
|
||||
<label>Status:</label>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
<%
|
||||
for (int curClient = 0; curClient < indexBean.getTunnelCount(); curClient++) {
|
||||
if (!indexBean.isClient(curClient)) continue;
|
||||
%>
|
||||
<div class="nameField rowItem">
|
||||
<label>Name:</label>
|
||||
<span class="text"><a href="edit.jsp?tunnel=<%=curClient%>" title="Edit Tunnel Settings for <%=indexBean.getTunnelName(curClient)%>"><%=indexBean.getTunnelName(curClient)%></a></span>
|
||||
</div>
|
||||
<div class="portField rowItem">
|
||||
<label>Port:</label>
|
||||
<span class="text"><%=indexBean.getClientPort(curClient)%></span>
|
||||
</div>
|
||||
<div class="typeField rowItem">
|
||||
<label>Type:</label>
|
||||
<span class="text"><%=indexBean.getTunnelType(curClient)%></span>
|
||||
</div>
|
||||
<div class="interfaceField rowItem">
|
||||
<label>Interface:</label>
|
||||
<span class="text"><%=indexBean.getClientInterface(curClient)%></span>
|
||||
</div>
|
||||
<div class="statusField rowItem">
|
||||
<label>Status:</label>
|
||||
<%
|
||||
switch (indexBean.getTunnelStatus(curClient)) {
|
||||
case IndexBean.STARTING:
|
||||
%><div class="statusStarting text">Starting...</div>
|
||||
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">Stop</a>
|
||||
<%
|
||||
break;
|
||||
case IndexBean.RUNNING:
|
||||
%><div class="statusRunning text">Running</div>
|
||||
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>">Stop</a>
|
||||
<%
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><div class="statusNotRunning text">Stopped</div>
|
||||
<a class="control" title="Start this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curClient%>">Start</a>
|
||||
<%
|
||||
break;
|
||||
}
|
||||
%></div>
|
||||
|
||||
<div class="destinationField rowItem">
|
||||
<label>Destination:</label>
|
||||
<input class="freetext" size="40" readonly="readonly" value="<%=indexBean.getClientDestination(curClient)%>" />
|
||||
</div>
|
||||
|
||||
<div class="descriptionField rowItem">
|
||||
<label>Description:</label>
|
||||
<div class="text"><%=indexBean.getTunnelDescription(curClient)%></div>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<form id="addNewClientTunnelForm" action="edit.jsp">
|
||||
<div class="toolbox">
|
||||
<label>Add new client tunnel:</label>
|
||||
<select name="type">
|
||||
<option value="client">Standard</option>
|
||||
<option value="httpclient">HTTP</option>
|
||||
<option value="ircclient">IRC</option>
|
||||
</select>
|
||||
<input class="control" type="submit" value="Create" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="localServerTunnelList" class="panel">
|
||||
<div class="header">
|
||||
<h4>Local Server Tunnels</h4>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div class="nameHeaderField rowItem">
|
||||
<label>Name:</label>
|
||||
</div>
|
||||
<div class="targetHeaderField rowItem">
|
||||
<label>Points at:</label>
|
||||
</div>
|
||||
<div class="previewHeaderField rowItem">
|
||||
<label>Preview:</label>
|
||||
</div>
|
||||
<div class="statusHeaderField rowItem">
|
||||
<label>Status:</label>
|
||||
</div>
|
||||
|
||||
<%
|
||||
for (int curServer = 0; curServer < indexBean.getTunnelCount(); curServer++) {
|
||||
if (indexBean.isClient(curServer)) continue;
|
||||
|
||||
%>
|
||||
<div class="nameField rowItem">
|
||||
<label>Name:</label>
|
||||
<span class="text"><a href="edit.jsp?tunnel=<%=curServer%>" title="Edit Server Tunnel Settings for <%=indexBean.getTunnelName(curServer)%>"><%=indexBean.getTunnelName(curServer)%></a></span>
|
||||
</div>
|
||||
<div class="targetField rowItem">
|
||||
<label>Points at:</label>
|
||||
<span class="text"><%=indexBean.getServerTarget(curServer)%></span>
|
||||
</div>
|
||||
<div class="previewField rowItem">
|
||||
<%
|
||||
if ("httpserver".equals(indexBean.getInternalType(curServer)) && indexBean.getTunnelStatus(curServer) == IndexBean.RUNNING) {
|
||||
%><label>Preview:</label>
|
||||
<a class="control" title="Preview this Tunnel" href="http://<%=(new java.util.Random()).nextLong()%>.i2p/?i2paddresshelper=<%=indexBean.getDestinationBase64(curServer)%>" target="_new">Preview</a>
|
||||
<%
|
||||
} else {
|
||||
%><span class="comment">No Preview</span>
|
||||
<%
|
||||
}
|
||||
%></div>
|
||||
<div class="statusField rowItem">
|
||||
<label>Status:</label>
|
||||
<%
|
||||
switch (indexBean.getTunnelStatus(curServer)) {
|
||||
case IndexBean.STARTING:
|
||||
%><div class="statusStarting text">Starting...</div>
|
||||
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">Stop</a>
|
||||
<%
|
||||
break;
|
||||
case IndexBean.RUNNING:
|
||||
%><div class="statusRunning text">Running</div>
|
||||
<a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>">Stop</a>
|
||||
<%
|
||||
break;
|
||||
case IndexBean.NOT_RUNNING:
|
||||
%><div class="statusNotRunning text">Stopped</div>
|
||||
<a class="control" title="Start this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curServer%>">Start</a>
|
||||
<%
|
||||
break;
|
||||
}
|
||||
%></div>
|
||||
|
||||
<div class="descriptionField rowItem">
|
||||
<label>Description:</label>
|
||||
<div class="text"><%=indexBean.getTunnelDescription(curServer)%></div>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<div class="separator">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<form id="addNewServerTunnelForm" action="edit.jsp">
|
||||
<div class="toolbox">
|
||||
<label>Add new server tunnel:</label>
|
||||
<select name="type">
|
||||
<option value="server">Standard</option>
|
||||
<option value="httpserver">HTTP</option>
|
||||
</select>
|
||||
<input class="control" type="submit" value="Create" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="globalOperationsPanel" class="panel">
|
||||
<div class="header"></div>
|
||||
<div class="footer">
|
||||
<div class="toolbox">
|
||||
<a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Stop%20all">Stop All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Start%20all">Start All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Restart%20all">Restart All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Reload%20configuration">Reload Config</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pageFooter">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -30,6 +30,7 @@ public class LogsHelper {
|
||||
buf.append("<code>\n");
|
||||
for (int i = msgs.size(); i > 0; i--) {
|
||||
String msg = (String)msgs.get(i - 1);
|
||||
msg = msg.replaceAll("<","<");
|
||||
buf.append("<li>");
|
||||
buf.append(msg);
|
||||
buf.append("</li>\n");
|
||||
@@ -46,6 +47,7 @@ public class LogsHelper {
|
||||
buf.append("<code>\n");
|
||||
for (int i = msgs.size(); i > 0; i--) {
|
||||
String msg = (String)msgs.get(i - 1);
|
||||
msg = msg.replaceAll("<","<");
|
||||
buf.append("<li>");
|
||||
buf.append(msg);
|
||||
buf.append("</li>\n");
|
||||
@@ -59,8 +61,10 @@ public class LogsHelper {
|
||||
String str = FileUtil.readTextFile("wrapper.log", 500, false);
|
||||
if (str == null)
|
||||
return "";
|
||||
else
|
||||
else {
|
||||
str = str.replaceAll("<","<");
|
||||
return "<pre>" + str + "</pre>";
|
||||
}
|
||||
}
|
||||
|
||||
public String getConnectionLogs() {
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
<h4>
|
||||
<a href="susimail/susimail">Susimail</a> |
|
||||
<a href="susidns/">SusiDNS</a> |
|
||||
<a href="susidns/index.jsp">SusiDNS</a> |
|
||||
<a href="syndie/">Syndie</a> |
|
||||
<a href="i2ptunnel/">I2PTunnel</a> |
|
||||
<a href="i2ptunnel/index.jsp">I2PTunnel</a> |
|
||||
<a href="tunnels.jsp">Tunnels</a> |
|
||||
<a href="profiles.jsp">Profiles</a> |
|
||||
<a href="netdb.jsp">NetDB</a> |
|
||||
|
||||
14
apps/routerconsole/jsp/viewtheme.jsp
Normal file
@@ -0,0 +1,14 @@
|
||||
<%
|
||||
String uri = request.getRequestURI();
|
||||
if (uri.endsWith(".css")) {
|
||||
response.setContentType("text/css");
|
||||
} else if (uri.endsWith(".png")) {
|
||||
response.setContentType("image/png");
|
||||
} else if (uri.endsWith(".gif")) {
|
||||
response.setContentType("image/gif");
|
||||
} else if (uri.endsWith(".jpg")) {
|
||||
response.setContentType("image/jpeg");
|
||||
}
|
||||
|
||||
net.i2p.util.FileUtil.readFile(uri, "./docs", response.getOutputStream());
|
||||
%>
|
||||
@@ -5,6 +5,13 @@
|
||||
|
||||
<web-app>
|
||||
<!-- precompiled servlets -->
|
||||
|
||||
<!-- yeah, i'm lazy, using a jsp instead of a servlet.. -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.router.web.jsp.viewtheme_jsp</servlet-name>
|
||||
<url-pattern>/themes/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
30
|
||||
|
||||
@@ -32,10 +32,16 @@
|
||||
<ant target="war" />
|
||||
</target>
|
||||
<target name="war" depends="builddep, compile, precompilejsp">
|
||||
<mkdir dir="./tmpwar" />
|
||||
<copy file="../../jdom/jdom.jar" tofile="./tmpwar/jdom.jar" />
|
||||
<copy file="../../rome/rome-0.7.jar" tofile="./tmpwar/rome-0.7.jar" />
|
||||
|
||||
<war destfile="../syndie.war" webxml="../jsp/web-out.xml">
|
||||
<fileset dir="../jsp/" includes="**/*" excludes=".nbintdb, web.xml, web-out.xml, web-fragment.xml, **/*.java, **/*.jsp" />
|
||||
<classes dir="./build/obj" />
|
||||
<lib dir="./tmpwar" />
|
||||
</war>
|
||||
<delete dir="./tmpwar" />
|
||||
</target>
|
||||
<target name="precompilejsp">
|
||||
<delete dir="../jsp/WEB-INF/" />
|
||||
|
||||
@@ -244,6 +244,7 @@ public class Archive {
|
||||
}
|
||||
|
||||
public List listEntries(BlogURI uri, String tag, SessionKey blogKey) {
|
||||
if (uri == null) return new ArrayList();
|
||||
return listEntries(uri.getKeyHash(), uri.getEntryId(), tag, blogKey);
|
||||
}
|
||||
public List listEntries(Hash blog, long entryId, String tag, SessionKey blogKey) {
|
||||
|
||||
@@ -19,6 +19,7 @@ class ArchiveIndexer {
|
||||
public static ArchiveIndex index(I2PAppContext ctx, Archive source) {
|
||||
Log log = ctx.logManager().getLog(ArchiveIndexer.class);
|
||||
LocalArchiveIndex rv = new LocalArchiveIndex(ctx);
|
||||
WritableThreadIndex threads = new WritableThreadIndex();
|
||||
rv.setGeneratedOn(ctx.clock().now());
|
||||
|
||||
File rootDir = source.getArchiveDir();
|
||||
@@ -79,6 +80,7 @@ class ArchiveIndexer {
|
||||
allEntries++;
|
||||
totalSize += entry.getCompleteSize();
|
||||
String entryTags[] = entry.getTags();
|
||||
threads.addEntry(entry.getURI(), entryTags);
|
||||
for (int t = 0; t < entryTags.length; t++) {
|
||||
if (!tags.containsKey(entryTags[t])) {
|
||||
tags.put(entryTags[t], new TreeMap());
|
||||
@@ -98,11 +100,18 @@ class ArchiveIndexer {
|
||||
parser.parse(entry.getEntry().getText(), rec);
|
||||
String reply = rec.getHeader(HTMLRenderer.HEADER_IN_REPLY_TO);
|
||||
if (reply != null) {
|
||||
BlogURI parent = new BlogURI(reply.trim());
|
||||
if ( (parent.getKeyHash() != null) && (parent.getEntryId() >= 0) )
|
||||
rv.addReply(parent, entry.getURI());
|
||||
else if (log.shouldLog(Log.WARN))
|
||||
log.warn("Parent of " + entry.getURI() + " is not valid: [" + reply.trim() + "]");
|
||||
String forceNewThread = rec.getHeader(HTMLRenderer.HEADER_FORCE_NEW_THREAD);
|
||||
if ( (forceNewThread != null) && (Boolean.valueOf(forceNewThread).booleanValue()) ) {
|
||||
// ignore the parent
|
||||
} else {
|
||||
BlogURI parent = new BlogURI(reply.trim());
|
||||
if ( (parent.getKeyHash() != null) && (parent.getEntryId() >= 0) ) {
|
||||
rv.addReply(parent, entry.getURI());
|
||||
threads.addParent(parent, entry.getURI());
|
||||
} else if (log.shouldLog(Log.WARN)) {
|
||||
log.warn("Parent of " + entry.getURI() + " is not valid: [" + reply.trim() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +159,11 @@ class ArchiveIndexer {
|
||||
rv.addNewestEntry(uri);
|
||||
}
|
||||
|
||||
threads.organizeTree();
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("Tree: \n" + threads.toString());
|
||||
rv.setThreadedIndex(threads);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ public class BlogManager {
|
||||
if (rootDir == null)
|
||||
rootDir = "./syndie";
|
||||
}
|
||||
_instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir);
|
||||
_instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir, false);
|
||||
_instance.getArchive().regenerateIndex();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
@@ -144,9 +145,12 @@ public class BlogManager {
|
||||
public BlogInfo createInfo(SigningPublicKey pub, SigningPrivateKey priv, String name, SigningPublicKey posters[],
|
||||
String description, String contactURL, String archives[], int edition) {
|
||||
Properties opts = new Properties();
|
||||
if (name == null) name = "";
|
||||
opts.setProperty("Name", name);
|
||||
if (description == null) description = "";
|
||||
opts.setProperty("Description", description);
|
||||
opts.setProperty("Edition", Integer.toString(edition));
|
||||
if (contactURL == null) contactURL = "";
|
||||
opts.setProperty("ContactURL", contactURL);
|
||||
for (int i = 0; archives != null && i < archives.length; i++)
|
||||
opts.setProperty("Archive." + i, archives[i]);
|
||||
@@ -231,7 +235,7 @@ public class BlogManager {
|
||||
Properties userProps = loadUserProps(files[i]);
|
||||
if (userProps == null)
|
||||
continue;
|
||||
User user = new User();
|
||||
User user = new User(_context);
|
||||
user.load(userProps);
|
||||
if (blog.equals(user.getBlog()))
|
||||
return user;
|
||||
@@ -251,7 +255,7 @@ public class BlogManager {
|
||||
Properties userProps = loadUserProps(files[i]);
|
||||
if (userProps == null)
|
||||
continue;
|
||||
User user = new User();
|
||||
User user = new User(_context);
|
||||
user.load(userProps);
|
||||
rv.add(user);
|
||||
}
|
||||
@@ -280,6 +284,23 @@ public class BlogManager {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean changePasswrd(User user, String oldPass, String pass0, String pass1) {
|
||||
boolean ok = user.changePassword(oldPass, pass0, pass1);
|
||||
if (ok)
|
||||
saveUser(user);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
public User login(String login, String pass) {
|
||||
User u = new User(_context);
|
||||
String ok = login(u, login, pass);
|
||||
if (User.LOGIN_OK.equals(ok))
|
||||
return u;
|
||||
else
|
||||
return new User(_context);
|
||||
}
|
||||
|
||||
public String login(User user, String login, String pass) {
|
||||
if ( (login == null) || (pass == null) ) return "<span class=\"b_loginMsgErr\">Login not specified</span>";
|
||||
Hash userHash = _context.sha().calculateHash(DataHelper.getUTF8(login));
|
||||
@@ -293,12 +314,19 @@ public class BlogManager {
|
||||
try {
|
||||
Properties props = loadUserProps(userFile);
|
||||
if (props == null) throw new IOException("Error reading " + userFile);
|
||||
return user.login(login, pass, props);
|
||||
String rv = user.login(login, pass, props);
|
||||
if (User.LOGIN_OK.equals(rv))
|
||||
_log.info("Login successful");
|
||||
else
|
||||
_log.info("Login failed: [" + rv + "]");
|
||||
return rv;
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error logging in", ioe);
|
||||
return "<span class=\"b_loginMsgErr\">Error logging in - corrupt userfile</span>";
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("User does not exist");
|
||||
return "<span class=\"b_loginMsgErr\">User does not exist</span>";
|
||||
}
|
||||
}
|
||||
@@ -324,23 +352,34 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
public boolean isConfigured() {
|
||||
File cfg = getConfigFile();
|
||||
return (cfg.exists());
|
||||
String p = _context.getProperty("syndie.singleUser");
|
||||
if(p==null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final boolean DEFAULT_IS_SINGLEUSER = true;
|
||||
|
||||
/**
|
||||
* If true, this syndie instance is meant for just one local user, so we don't need
|
||||
* to password protect registration, remote.jsp, or admin.jsp
|
||||
*
|
||||
*/
|
||||
public boolean isSingleUser() {
|
||||
if (!isConfigured()) return DEFAULT_IS_SINGLEUSER;
|
||||
String isSingle = _context.getProperty("syndie.singleUser");
|
||||
return ( (isSingle != null) && (Boolean.valueOf(isSingle).booleanValue()) );
|
||||
}
|
||||
|
||||
public String getDefaultProxyHost() { return _context.getProperty("syndie.defaultProxyHost", ""); }
|
||||
public String getDefaultProxyPort() { return _context.getProperty("syndie.defaultProxyPort", ""); }
|
||||
public String[] getUpdateArchives() { return _context.getProperty("syndie.updateArchives", "").split(","); }
|
||||
public String getDefaultProxyHost() { return _context.getProperty("syndie.defaultProxyHost", "localhost"); }
|
||||
public String getDefaultProxyPort() { return _context.getProperty("syndie.defaultProxyPort", "4444"); }
|
||||
public String[] getUpdateArchives() {
|
||||
String str = _context.getProperty("syndie.updateArchives", "");
|
||||
if ( (str != null) && (str.trim().length() > 0) )
|
||||
return str.split(",");
|
||||
else
|
||||
return new String[0];
|
||||
}
|
||||
public boolean getImportAddresses() { return _context.getProperty("syndie.importAddresses", "false").equals("true"); }
|
||||
public int getUpdateDelay() {
|
||||
int delay = Integer.parseInt(_context.getProperty("syndie.updateDelay", "12"));
|
||||
@@ -348,6 +387,149 @@ public class BlogManager {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public List getRssFeeds() {
|
||||
List feedList = new ArrayList();
|
||||
int i=0;
|
||||
while(true) {
|
||||
String url = _context.getProperty("syndie.rssFeed."+i+".url");
|
||||
String blog = _context.getProperty("syndie.rssFeed."+i+".blog");
|
||||
String tagPrefix = _context.getProperty("syndie.rssFeed."+i+".tagPrefix");
|
||||
if(url==null || blog==null || tagPrefix==null)
|
||||
break;
|
||||
String feed[] = new String[3];
|
||||
feed[0]=url.trim();
|
||||
feed[1]=blog.trim();
|
||||
feed[2]=tagPrefix.trim();
|
||||
feedList.add(feed);
|
||||
i++;
|
||||
}
|
||||
return feedList;
|
||||
}
|
||||
public boolean addRssFeed(String url, String blog, String tagPrefix) {
|
||||
|
||||
List feedList = getRssFeeds();
|
||||
int nextIdx=feedList.size();
|
||||
|
||||
String baseFeedProp="syndie.rssFeed."+nextIdx;
|
||||
System.setProperty(baseFeedProp+".url",url);
|
||||
System.setProperty(baseFeedProp+".blog",blog);
|
||||
System.setProperty(baseFeedProp+".tagPrefix",tagPrefix);
|
||||
_log.info("addRssFeed("+nextIdx+"): "+url);
|
||||
writeConfig();
|
||||
Updater.wakeup();
|
||||
return true;
|
||||
}
|
||||
public boolean deleteRssFeed(String url, String blog, String tagPrefix) {
|
||||
List feedList = getRssFeeds();
|
||||
Iterator iter = feedList.iterator();
|
||||
int idx=0;
|
||||
while(iter.hasNext()) {
|
||||
String fields[] = (String[])iter.next();
|
||||
if(fields[0].equals(url) &&
|
||||
fields[1].equals(blog) &&
|
||||
fields[2].equals(tagPrefix)) {
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
// copy any remaining to idx-1
|
||||
while(iter.hasNext()) {
|
||||
String fields[] = (String[])iter.next();
|
||||
String baseFeedProp="syndie.rssFeed."+idx;
|
||||
System.setProperty(baseFeedProp+".url",fields[0]);
|
||||
System.setProperty(baseFeedProp+".blog",fields[1]);
|
||||
System.setProperty(baseFeedProp+".tagPrefix",fields[2]);
|
||||
idx++;
|
||||
}
|
||||
|
||||
// Delete last idx from properties
|
||||
String baseFeedProp="syndie.rssFeed."+idx;
|
||||
System.getProperties().remove(baseFeedProp+".url");
|
||||
System.getProperties().remove(baseFeedProp+".blog");
|
||||
System.getProperties().remove(baseFeedProp+".tagPrefix");
|
||||
_log.info("deleteRssFeed("+idx+"): "+url);
|
||||
writeConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String DEFAULT_LOGIN = "default";
|
||||
private static final String DEFAULT_PASS = "";
|
||||
|
||||
private static final String PROP_DEFAULT_LOGIN = "syndie.defaultSingleUserLogin";
|
||||
private static final String PROP_DEFAULT_PASS = "syndie.defaultSingleUserPass";
|
||||
|
||||
public String getDefaultLogin() {
|
||||
String login = _context.getProperty(PROP_DEFAULT_LOGIN);
|
||||
if ( (login == null) || (login.trim().length() <= 0) )
|
||||
login = DEFAULT_LOGIN;
|
||||
return login;
|
||||
}
|
||||
public String getDefaultPass() {
|
||||
String pass = _context.getProperty(PROP_DEFAULT_PASS);
|
||||
if ( (pass == null) || (pass.trim().length() <= 0) )
|
||||
pass = DEFAULT_PASS;
|
||||
return pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are a single user instance, when we create the default user, give them
|
||||
* addressbook entries for each of the following, *and* schedule them for syndication
|
||||
*
|
||||
*/
|
||||
private static final String DEFAULT_SINGLE_USER_ARCHIVES[] = new String[] {
|
||||
"http://syndiemedia.i2p/archive/archive.txt"
|
||||
, "http://gloinsblog.i2p/archive/archive.txt"
|
||||
, "http://glog.i2p/archive/archive.txt"
|
||||
};
|
||||
|
||||
public User getDefaultUser() {
|
||||
User user = new User(_context);
|
||||
getDefaultUser(user);
|
||||
return user;
|
||||
}
|
||||
public void getDefaultUser(User user) {
|
||||
if (isSingleUser()) {
|
||||
Hash userHash = _context.sha().calculateHash(DataHelper.getUTF8(getDefaultLogin()));
|
||||
File userFile = new File(_userDir, Base64.encode(userHash.getData()));
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Attempting to login to the default user: " + userFile.getAbsolutePath());
|
||||
|
||||
if (userFile.exists()) {
|
||||
Properties props = loadUserProps(userFile);
|
||||
if (props == null) {
|
||||
user.invalidate();
|
||||
_log.error("Error reading the default user file: " + userFile);
|
||||
return;
|
||||
}
|
||||
String ok = user.login(getDefaultLogin(), getDefaultPass(), props);
|
||||
if (User.LOGIN_OK.equals(ok)) {
|
||||
return;
|
||||
} else {
|
||||
user.invalidate();
|
||||
_log.error("Error logging into the default user: " + ok);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
String ok = register(user, getDefaultLogin(), getDefaultPass(), "", "default", "Default Syndie blog", "");
|
||||
if (User.LOGIN_OK.equals(ok)) {
|
||||
_log.info("Default user created: " + user);
|
||||
for (int i = 0; i < DEFAULT_SINGLE_USER_ARCHIVES.length; i++)
|
||||
user.getPetNameDB().add(new PetName("DefaultArchive" + i, "syndie", "syndiearchive", DEFAULT_SINGLE_USER_ARCHIVES[i]));
|
||||
scheduleSyndication(DEFAULT_SINGLE_USER_ARCHIVES);
|
||||
saveUser(user);
|
||||
return;
|
||||
} else {
|
||||
user.invalidate();
|
||||
_log.error("Error registering the default user: " + ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean authorizeAdmin(String pass) {
|
||||
if (isSingleUser()) return true;
|
||||
String admin = getAdminPasswordHash();
|
||||
@@ -370,7 +552,8 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
public void configure(String registrationPassword, String remotePassword, String adminPass, String defaultSelector,
|
||||
String defaultProxyHost, int defaultProxyPort, boolean isSingleUser, Properties opts) {
|
||||
String defaultProxyHost, int defaultProxyPort, boolean isSingleUser, Properties opts,
|
||||
String defaultUser, String defaultPass) {
|
||||
File cfg = getConfigFile();
|
||||
Writer out = null;
|
||||
try {
|
||||
@@ -387,7 +570,15 @@ public class BlogManager {
|
||||
out.write("syndie.defaultProxyHost="+defaultProxyHost.trim() + "\n");
|
||||
if (defaultProxyPort > 0)
|
||||
out.write("syndie.defaultProxyPort="+defaultProxyPort + "\n");
|
||||
out.write("syndie.singleUser=" + isSingleUser + "\n");
|
||||
|
||||
if ( (defaultUser == null) || (defaultUser.length() <= 0) )
|
||||
defaultUser = getDefaultLogin();
|
||||
if (defaultPass == null)
|
||||
defaultPass = getDefaultPass();
|
||||
out.write("syndie.defaultSingleUserLogin="+defaultUser+"\n");
|
||||
out.write("syndie.defaultSingleUserPass="+defaultPass+"\n");
|
||||
|
||||
out.write("syndie.singleUser=" + isSingleUser + "\n"); // Used also in isConfigured()
|
||||
if (opts != null) {
|
||||
for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
@@ -444,6 +635,13 @@ public class BlogManager {
|
||||
if (!user.getAuthenticated()) return;
|
||||
storeUser(user);
|
||||
}
|
||||
public User register(String login, String password, String registrationPassword, String blogName, String blogDescription, String contactURL) {
|
||||
User user = new User(_context);
|
||||
if (User.LOGIN_OK.equals(register(user, login, password, registrationPassword, blogName, blogDescription, contactURL)))
|
||||
return user;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
public String register(User user, String login, String password, String registrationPassword, String blogName, String blogDescription, String contactURL) {
|
||||
System.err.println("Register [" + login + "] pass [" + password + "] name [" + blogName + "] descr [" + blogDescription + "] contact [" + contactURL + "] regPass [" + registrationPassword + "]");
|
||||
String hashedRegistrationPassword = getRegistrationPasswordHash();
|
||||
@@ -525,10 +723,13 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
public BlogURI createBlogEntry(User user, String subject, String tags, String entryHeaders, String sml) {
|
||||
return createBlogEntry(user, subject, tags, entryHeaders, sml, null, null, null);
|
||||
return createBlogEntry(user, true, subject, tags, entryHeaders, sml, null, null, null);
|
||||
}
|
||||
public BlogURI createBlogEntry(User user, String subject, String tags, String entryHeaders, String sml, List fileNames, List fileStreams, List fileTypes) {
|
||||
if (!user.getAuthenticated()) return null;
|
||||
return createBlogEntry(user, true, subject, tags, entryHeaders, sml, fileNames, fileStreams, fileTypes);
|
||||
}
|
||||
public BlogURI createBlogEntry(User user, boolean shouldAuthenticate, String subject, String tags, String entryHeaders, String sml, List fileNames, List fileStreams, List fileTypes) {
|
||||
if (shouldAuthenticate && !user.getAuthenticated()) return null;
|
||||
BlogInfo info = getArchive().getBlogInfo(user.getBlog());
|
||||
if (info == null) return null;
|
||||
SigningPrivateKey privkey = getMyPrivateKey(info);
|
||||
@@ -563,6 +764,8 @@ public class BlogManager {
|
||||
int split = line.indexOf('=');
|
||||
int split2 = line.indexOf(':');
|
||||
if ( (split < 0) || ( (split2 > 0) && (split2 < split) ) ) split = split2;
|
||||
if ( (split < 0) && (split2 < 0) )
|
||||
continue;
|
||||
String key = line.substring(0,split).trim();
|
||||
String val = line.substring(split+1).trim();
|
||||
raw.append(key).append(": ").append(val).append('\n');
|
||||
@@ -601,7 +804,10 @@ public class BlogManager {
|
||||
if (ok) {
|
||||
getArchive().regenerateIndex();
|
||||
user.setMostRecentEntry(entryId);
|
||||
saveUser(user);
|
||||
if(shouldAuthenticate)
|
||||
saveUser(user);
|
||||
else
|
||||
storeUser(user);
|
||||
return uri;
|
||||
} else {
|
||||
return null;
|
||||
@@ -748,6 +954,20 @@ public class BlogManager {
|
||||
System.setProperty("syndie.updateArchives", buf.toString());
|
||||
Updater.wakeup();
|
||||
}
|
||||
public void scheduleSyndication(String locations[]) {
|
||||
String archives[] = getUpdateArchives();
|
||||
HashSet locs = new HashSet();
|
||||
for (int i = 0; (archives != null) && (i < archives.length); i++)
|
||||
locs.add(archives[i]);
|
||||
for (int i = 0; (locations != null) && (i < locations.length); i++)
|
||||
locs.add(locations[i]);
|
||||
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
for (Iterator iter = locs.iterator(); iter.hasNext(); )
|
||||
buf.append(iter.next().toString().trim()).append(',');
|
||||
System.setProperty("syndie.updateArchives", buf.toString());
|
||||
Updater.wakeup();
|
||||
}
|
||||
public void unscheduleSyndication(String location) {
|
||||
String archives[] = getUpdateArchives();
|
||||
if ( (archives != null) && (archives.length > 0) ) {
|
||||
|
||||
43
apps/syndie/java/src/net/i2p/syndie/HeaderReceiver.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.syndie.sml.SMLParser;
|
||||
|
||||
public class HeaderReceiver implements SMLParser.EventReceiver {
|
||||
private Properties _headers;
|
||||
public HeaderReceiver() { _headers = null; }
|
||||
public String getHeader(String name) { return (_headers != null ? _headers.getProperty(name) : null); }
|
||||
public void receiveHeader(String header, String value) {
|
||||
if (_headers == null) _headers = new Properties();
|
||||
_headers.setProperty(header, value);
|
||||
}
|
||||
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText) {}
|
||||
public void receiveArchive(String name, String description, String locationSchema, String location, String postingKey, String anchorText) {}
|
||||
public void receiveAttachment(int id, String anchorText) {}
|
||||
public void receiveBegin() {}
|
||||
public void receiveBlog(String name, String blogKeyHash, String blogPath, long blogEntryId, List blogArchiveLocations, String anchorText) {}
|
||||
public void receiveBold(String text) {}
|
||||
public void receiveCode(String text, String codeLocationSchema, String codeLocation) {}
|
||||
public void receiveCut(String summaryText) {}
|
||||
public void receiveEnd() {}
|
||||
public void receiveGT() {}
|
||||
public void receiveH1(String text) {}
|
||||
public void receiveH2(String text) {}
|
||||
public void receiveH3(String text) {}
|
||||
public void receiveH4(String text) {}
|
||||
public void receiveH5(String text) {}
|
||||
public void receiveHR() {}
|
||||
public void receiveHeaderEnd() {}
|
||||
public void receiveImage(String alternateText, int attachmentId) {}
|
||||
public void receiveItalic(String text) {}
|
||||
public void receiveLT() {}
|
||||
public void receiveLeftBracket() {}
|
||||
public void receiveLink(String schema, String location, String text) {}
|
||||
public void receiveNewline() {}
|
||||
public void receivePlain(String text) {}
|
||||
public void receivePre(String text) {}
|
||||
public void receiveQuote(String text, String whoQuoted, String quoteLocationSchema, String quoteLocation) {}
|
||||
public void receiveRightBracket() {}
|
||||
public void receiveUnderline(String text) {}
|
||||
}
|
||||
@@ -10,12 +10,10 @@ import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
//import sun.security.provider.SHA;
|
||||
|
||||
import com.sun.syndication.feed.synd.SyndCategory;
|
||||
import com.sun.syndication.feed.synd.SyndContent;
|
||||
@@ -27,9 +25,15 @@ import com.sun.syndication.io.XmlReader;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.syndie.data.BlogURI;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class Sucker {
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(Sucker.class);
|
||||
private String urlToLoad;
|
||||
private String outputDir="./sucker_out";
|
||||
private String historyPath="./sucker.history";
|
||||
@@ -46,9 +50,52 @@ public class Sucker {
|
||||
private boolean pendingEndLink;
|
||||
private boolean shouldProxy;
|
||||
private int proxyPortNum;
|
||||
private String blog;
|
||||
private boolean pushToSyndie;
|
||||
private long messageNumber=0;
|
||||
private BlogManager bm;
|
||||
private User user;
|
||||
|
||||
public Sucker() {}
|
||||
//
|
||||
private List fileNames;
|
||||
private List fileStreams;
|
||||
private List fileTypes;
|
||||
private List tempFiles; // deleted after finished push
|
||||
private boolean stripNewlines;
|
||||
|
||||
public Sucker() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for BlogManager.
|
||||
*/
|
||||
public Sucker(String[] strings) throws IllegalArgumentException {
|
||||
pushToSyndie=true;
|
||||
urlToLoad = strings[0];
|
||||
blog = strings[1];
|
||||
feedTag = strings[2];
|
||||
outputDir = "blog-"+blog;
|
||||
try {
|
||||
historyPath=BlogManager.instance().getRootDir().getCanonicalPath()+"/rss.history";
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
proxyPort = BlogManager.instance().getDefaultProxyPort();
|
||||
proxyHost = BlogManager.instance().getDefaultProxyHost();
|
||||
|
||||
bm = BlogManager.instance();
|
||||
Hash blogHash = new Hash();
|
||||
try {
|
||||
blogHash.fromBase64(blog);
|
||||
} catch (DataFormatException e1) {
|
||||
throw new IllegalArgumentException("ooh, bad $blog");
|
||||
}
|
||||
|
||||
user = bm.getUser(blogHash);
|
||||
if(user==null)
|
||||
throw new IllegalArgumentException("wtf, user==null? hash:"+blogHash);
|
||||
}
|
||||
|
||||
public boolean parseArgs(String args[]) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if ("--load".equals(args[i]))
|
||||
@@ -77,58 +124,62 @@ public class Sucker {
|
||||
|
||||
if (urlToLoad == null)
|
||||
return false;
|
||||
|
||||
// Find base url, gah HELP
|
||||
int idx=urlToLoad.length();
|
||||
int x=urlToLoad.indexOf('?');
|
||||
if(x>0)
|
||||
idx=x;
|
||||
while(idx>0)
|
||||
{
|
||||
idx--;
|
||||
if(urlToLoad.charAt(idx)=='/')
|
||||
break;
|
||||
}
|
||||
if(idx==0)
|
||||
idx=x;
|
||||
baseUrl=urlToLoad.substring(0,idx);
|
||||
|
||||
System.out.println("Processing: "+urlToLoad);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch urlToLoad and call convertToHtml() on any new entries.
|
||||
*/
|
||||
public void suck() {
|
||||
SyndFeed feed;
|
||||
File fetched=null;
|
||||
|
||||
tempFiles = new ArrayList();
|
||||
|
||||
// Find base url
|
||||
int idx=urlToLoad.lastIndexOf('/');
|
||||
if(idx>0)
|
||||
baseUrl=urlToLoad.substring(0,idx);
|
||||
else
|
||||
baseUrl=urlToLoad;
|
||||
|
||||
infoLog("Processing: "+urlToLoad);
|
||||
debugLog("Base url: "+baseUrl);
|
||||
|
||||
//
|
||||
try {
|
||||
|
||||
// Create outputDir if missing
|
||||
File f = new File(outputDir);
|
||||
f.mkdirs();
|
||||
File lastIdFile=null;
|
||||
|
||||
// Get next message number to use (for messageId in history only)
|
||||
if(!pushToSyndie) {
|
||||
|
||||
lastIdFile = new File(historyPath + ".lastId");
|
||||
if (!lastIdFile.exists())
|
||||
lastIdFile.createNewFile();
|
||||
|
||||
FileInputStream fis = new FileInputStream(lastIdFile);
|
||||
String number = readLine(fis);
|
||||
try {
|
||||
messageNumber = Integer.parseInt(number);
|
||||
} catch (NumberFormatException e) {
|
||||
messageNumber = 0;
|
||||
}
|
||||
|
||||
// Create outputDir if missing
|
||||
File f = new File(outputDir);
|
||||
f.mkdirs();
|
||||
} else {
|
||||
messageNumber=bm.getNextBlogEntry(user);
|
||||
}
|
||||
|
||||
_log.debug("message number: " + messageNumber);
|
||||
|
||||
// Create historyFile if missing
|
||||
historyFile = new File(historyPath);
|
||||
if (!historyFile.exists())
|
||||
historyFile.createNewFile();
|
||||
|
||||
int messageNumber;
|
||||
|
||||
File lastIdFile = new File(historyPath + ".lastId");
|
||||
if (!lastIdFile.exists())
|
||||
lastIdFile.createNewFile();
|
||||
|
||||
FileInputStream fis = new FileInputStream(lastIdFile);
|
||||
String number = readLine(fis);
|
||||
try {
|
||||
messageNumber = Integer.parseInt(number);
|
||||
} catch (NumberFormatException e) {
|
||||
messageNumber = 0;
|
||||
}
|
||||
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
shouldProxy = false;
|
||||
proxyPortNum = -1;
|
||||
if ( (proxyHost != null) && (proxyPort != null) ) {
|
||||
@@ -140,104 +191,102 @@ public class Sucker {
|
||||
nfe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// fetch
|
||||
int numRetries = 2;
|
||||
// perhaps specify a temp dir?
|
||||
File fetched = File.createTempFile("sucker", ".fetch");
|
||||
fetched.deleteOnExit();
|
||||
// we use eepGet, since it retries and doesn't leak DNS requests like URL does
|
||||
fetched = File.createTempFile("sucker", ".fetch");
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), shouldProxy, proxyHost, proxyPortNum,
|
||||
numRetries, fetched.getAbsolutePath(), urlToLoad);
|
||||
SuckerFetchListener lsnr = new SuckerFetchListener();
|
||||
get.addStatusListener(lsnr);
|
||||
|
||||
_log.debug("fetching [" + urlToLoad + "] / " + shouldProxy + "/" + proxyHost + "/" + proxyHost);
|
||||
|
||||
get.fetch();
|
||||
_log.debug("fetched: " + get.getNotModified() + "/" + get.getETag());
|
||||
boolean ok = lsnr.waitForSuccess();
|
||||
if (!ok) {
|
||||
_log.debug("success? " + ok);
|
||||
System.err.println("Unable to retrieve the url after " + numRetries + " tries.");
|
||||
fetched.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
_log.debug("fetched successfully? " + ok);
|
||||
if(get.getNotModified()) {
|
||||
debugLog("not modified, saving network bytes from useless fetch");
|
||||
fetched.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
// Build entry list from fetched rss file
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
feed = input.build(new XmlReader(fetched));
|
||||
|
||||
List entries = feed.getEntries();
|
||||
|
||||
_log.debug("entries: " + entries.size());
|
||||
|
||||
FileOutputStream hos = new FileOutputStream(historyFile, true);
|
||||
|
||||
ListIterator iter = entries.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
// Process list backwards to get syndie to display the
|
||||
// entries in the right order. (most recent at top)
|
||||
for (int i = entries.size()-1; i >= 0; i--) {
|
||||
SyndEntry e = (SyndEntry) entries.get(i);
|
||||
|
||||
attachmentCounter=0;
|
||||
|
||||
SyndEntry e = (SyndEntry) iter.next();
|
||||
// Calculate messageId
|
||||
String feedHash = sha1(urlToLoad);
|
||||
String itemHash = sha1(e.getTitle() + e.getDescription());
|
||||
Date d = e.getPublishedDate();
|
||||
String time;
|
||||
if(d!=null)
|
||||
time = "" + d.getTime();
|
||||
else
|
||||
time = "" + new Date().getTime();
|
||||
|
||||
String outputFileName = outputDir + "/" + messageNumber;
|
||||
|
||||
/*
|
||||
* $feedHash:$itemHash:$time:$outputfile. $feedHash would be the
|
||||
* hash (md5? sha1? sha2?) of the $urlToFeed, $itemHash is some
|
||||
* hash of the SyndEntry, $time would be the time that the entry
|
||||
* was posted $outputfile would be the $outputdir/$uniqueid
|
||||
*/
|
||||
String messageId = feedHash + ":" + itemHash + ":" + time + ":"
|
||||
+ outputFileName;
|
||||
|
||||
// Check if we already have this
|
||||
if (!existsInHistory(messageId)) {
|
||||
System.out.println("new: " + messageId);
|
||||
|
||||
if (convertToSml(e, ""+messageNumber)) {
|
||||
|
||||
if (pushScript != null) {
|
||||
if (!execPushScript(""+messageNumber, time)) {
|
||||
System.out.println("################## push failed");
|
||||
}else {
|
||||
System.out.println("push success");
|
||||
hos.write(messageId.getBytes());
|
||||
hos.write("\n".getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
messageNumber++;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Syndicate entry: " + e.getLink());
|
||||
|
||||
String messageId = convertToSml(e);
|
||||
if (messageId!=null) {
|
||||
hos.write(messageId.getBytes());
|
||||
hos.write("\n".getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(lastIdFile);
|
||||
fos.write(("" + messageNumber).getBytes());
|
||||
|
||||
if(!pushToSyndie) {
|
||||
FileOutputStream fos = new FileOutputStream(lastIdFile);
|
||||
fos.write(("" + messageNumber).getBytes());
|
||||
}
|
||||
|
||||
_log.debug("done fetching");
|
||||
} catch (MalformedURLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (FeedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Done.");
|
||||
if(fetched!=null)
|
||||
fetched.delete();
|
||||
debugLog("Done.");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Sucker sucker = new Sucker();
|
||||
boolean ok = sucker.parseArgs(args);
|
||||
if (!ok) {
|
||||
usage();
|
||||
return;
|
||||
System.out.println("sucker --load $urlToFeed \n"
|
||||
+ "--proxyhost <host> \n"
|
||||
+ "--proxyport <port> \n"
|
||||
+ "--importenclosures true \n"
|
||||
+ "--importrefs true \n"
|
||||
+ "--tag feed \n"
|
||||
+ "--outputdir ./sucker_out \n"
|
||||
+ "--exec pushscript.sh OUTPUTDIR UNIQUEID ENTRYTIMESTAMP \n"
|
||||
+ "--history ./sucker.history");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
sucker.suck();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the specified script with "$outputDir $id and $time".
|
||||
*/
|
||||
private boolean execPushScript(String id, String time) {
|
||||
try {
|
||||
String ls_str;
|
||||
@@ -247,11 +296,17 @@ public class Sucker {
|
||||
|
||||
// get its output (your input) stream
|
||||
|
||||
DataInputStream ls_in = new DataInputStream(pushScript_proc.getInputStream());
|
||||
InputStream ls_in = pushScript_proc.getInputStream();
|
||||
|
||||
try {
|
||||
while ((ls_str = ls_in.readLine()) != null) {
|
||||
System.out.println(pushScript + ": " + ls_str);
|
||||
StringBuffer buf = new StringBuffer();
|
||||
while (true) {
|
||||
boolean eof = DataHelper.readLine(ls_in, buf);
|
||||
if (buf.length() > 0)
|
||||
infoLog(pushScript + ": " + buf.toString());
|
||||
buf.setLength(0);
|
||||
if (eof)
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
@@ -261,7 +316,6 @@ public class Sucker {
|
||||
if(pushScript_proc.exitValue()==0)
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
@@ -271,40 +325,59 @@ public class Sucker {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean convertToSml(SyndEntry e, String messageName) {
|
||||
/**
|
||||
* Converts the SyndEntry e to sml and fetches any images as attachments
|
||||
*/
|
||||
private String convertToSml(SyndEntry e) {
|
||||
String subject;
|
||||
|
||||
// Create message
|
||||
FileOutputStream fos;
|
||||
messagePath=outputDir+"/"+messageName;
|
||||
stripNewlines=false;
|
||||
|
||||
// Calculate messageId, and check if we have got the message already
|
||||
String feedHash = sha1(urlToLoad);
|
||||
String itemHash = sha1(e.getTitle() + e.getDescription());
|
||||
Date d = e.getPublishedDate();
|
||||
String time;
|
||||
if(d!=null)
|
||||
time = "" + d.getTime();
|
||||
else
|
||||
time = "" + new Date().getTime();
|
||||
String outputFileName = outputDir + "/" + messageNumber;
|
||||
String messageId = feedHash + ":" + itemHash + ":" + time + ":" + outputFileName;
|
||||
// Check if we already have this
|
||||
if (existsInHistory(messageId))
|
||||
return null;
|
||||
|
||||
infoLog("new: " + messageId);
|
||||
|
||||
try {
|
||||
fos = new FileOutputStream(messagePath);
|
||||
|
||||
String sml;
|
||||
sml = "Subject: " + e.getTitle() + "\n";
|
||||
String sml="";
|
||||
subject=e.getTitle();
|
||||
List cats = e.getCategories();
|
||||
Iterator iter = cats.iterator();
|
||||
String tags = feedTag;
|
||||
while (iter.hasNext()) {
|
||||
SyndCategory c = (SyndCategory) iter.next();
|
||||
debugLog("Name: "+c.getName());
|
||||
debugLog("uri:"+c.getTaxonomyUri());
|
||||
String tag=c.getName();
|
||||
tag=tag.replaceAll("[^a-zA-z.-_:]","_");
|
||||
tags += "\t" + feedTag + "." + tag;
|
||||
}
|
||||
sml += "Tags: " + tags + "\n";
|
||||
sml += "\n";
|
||||
|
||||
SyndContent content;
|
||||
|
||||
List l = e.getContents();
|
||||
if(l!=null)
|
||||
{
|
||||
System.out.println("There is content");
|
||||
debugLog("There is content");
|
||||
iter = l.iterator();
|
||||
while(iter.hasNext())
|
||||
{
|
||||
content = (SyndContent)iter.next();
|
||||
String c = content.getValue();
|
||||
System.out.println("Content: "+c);
|
||||
debugLog("Content: "+c);
|
||||
sml += htmlToSml(c);
|
||||
sml += "\n";
|
||||
}
|
||||
@@ -314,66 +387,141 @@ public class Sucker {
|
||||
source=baseUrl+source;
|
||||
sml += "[link schema=\"web\" location=\""+source+"\"]source[/link]\n";
|
||||
|
||||
fos.write(sml.getBytes());
|
||||
if(pushToSyndie) {
|
||||
debugLog("user.blog: "+user.getBlogStr());
|
||||
debugLog("user.id: "+bm.getNextBlogEntry(user));
|
||||
debugLog("subject: "+subject);
|
||||
debugLog("tags: "+tags);
|
||||
debugLog("sml: "+sml);
|
||||
debugLog("");
|
||||
BlogURI uri = bm.createBlogEntry(
|
||||
user,
|
||||
false,
|
||||
subject,
|
||||
tags,
|
||||
null,
|
||||
sml,
|
||||
fileNames,
|
||||
fileStreams,
|
||||
fileTypes);
|
||||
|
||||
return true;
|
||||
if(uri==null) {
|
||||
errorLog("pushToSyndie failure.");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
infoLog("pushToSyndie success, uri: "+uri.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
FileOutputStream fos;
|
||||
fos = new FileOutputStream(messagePath);
|
||||
sml=subject + "\nTags: " + tags + "\n\n" + sml;
|
||||
fos.write(sml.getBytes());
|
||||
if (pushScript != null) {
|
||||
if (!execPushScript(""+messageNumber, time)) {
|
||||
errorLog("push script failed");
|
||||
} else {
|
||||
infoLog("push script success: nr "+messageNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
messageNumber++;
|
||||
deleteTempFiles();
|
||||
return messageId;
|
||||
} catch (FileNotFoundException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
} catch (IOException e2) {
|
||||
// TODO Auto-generated catch block
|
||||
e2.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
deleteTempFiles();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void deleteTempFiles() {
|
||||
Iterator iter = tempFiles.iterator();
|
||||
while(iter.hasNext()) {
|
||||
File tempFile = (File)iter.next();
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private String htmlToSml(String html) {
|
||||
|
||||
String sml="";
|
||||
int i;
|
||||
int i=0;
|
||||
|
||||
pendingEndLink=false;
|
||||
|
||||
for(i=0;i<html.length();)
|
||||
while(i<html.length())
|
||||
{
|
||||
if(html.charAt(i)=='<')
|
||||
{
|
||||
//System.out.println("html: "+html.substring(i));
|
||||
char c=html.charAt(i);
|
||||
switch(c) {
|
||||
case '<':
|
||||
//log("html: "+html.substring(i));
|
||||
|
||||
int tagLen = findTagLen(html.substring(i));
|
||||
if(tagLen<=0)
|
||||
{
|
||||
System.out.println("Bad html? ("+html+")");
|
||||
break;
|
||||
if(tagLen<=0) {
|
||||
// did not find anything that looks like tag, treat it like text
|
||||
sml+="<";
|
||||
break;
|
||||
}
|
||||
//
|
||||
String htmlTag = html.substring(i,i+tagLen);
|
||||
|
||||
//System.out.println("htmlTag: "+htmlTag);
|
||||
//log("htmlTag: "+htmlTag);
|
||||
|
||||
String smlTag = htmlTagToSmlTag(htmlTag);
|
||||
if(smlTag!=null)
|
||||
if(smlTag!=null) {
|
||||
sml+=smlTag;
|
||||
i+=tagLen;
|
||||
//System.out.println("tagLen: "+tagLen);
|
||||
sml+=" ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sml+=html.charAt(i++);
|
||||
i+=tagLen;
|
||||
sml+=" ";
|
||||
continue;
|
||||
}
|
||||
// Unrecognized tag, treat it as text
|
||||
sml+="<";
|
||||
break;
|
||||
case '\r':
|
||||
if(!stripNewlines)
|
||||
sml+='\r';
|
||||
break;
|
||||
case '\n':
|
||||
if(!stripNewlines)
|
||||
sml+='\n';
|
||||
break;
|
||||
case '[':
|
||||
sml+="[";
|
||||
break;
|
||||
case ']':
|
||||
sml+="]";
|
||||
break;
|
||||
default:
|
||||
sml+=c;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return sml;
|
||||
}
|
||||
|
||||
private String htmlTagToSmlTag(String htmlTag) {
|
||||
final String ignoreTags[] = {
|
||||
"span",
|
||||
"tr",
|
||||
"td",
|
||||
"th",
|
||||
"div",
|
||||
"input",
|
||||
"ul"
|
||||
};
|
||||
htmlTag = htmlTag.replaceAll("\\[","[").replaceAll("\\]","]");
|
||||
String ret="";
|
||||
String htmlTagLowerCase=htmlTag.toLowerCase();
|
||||
|
||||
if(importEnclosures && htmlTagLowerCase.startsWith("<img"))
|
||||
if(htmlTagLowerCase.startsWith("<img"))
|
||||
{
|
||||
System.out.println("Found image tag: "+htmlTag);
|
||||
debugLog("Found image tag: "+htmlTag);
|
||||
int a,b;
|
||||
a=htmlTagLowerCase.indexOf("src=\"")+5;
|
||||
b=a+1;
|
||||
@@ -381,9 +529,9 @@ public class Sucker {
|
||||
b++;
|
||||
String imageLink=htmlTag.substring(a,b);
|
||||
|
||||
if(pendingEndLink) {
|
||||
if(pendingEndLink) { // <a href="..."><img src="..."></a> -> [link][/link][img][/img]
|
||||
ret="[/link]";
|
||||
pendingEndLink=false;
|
||||
pendingEndLink=false;
|
||||
}
|
||||
|
||||
ret += "[img attachment=\""+""+ attachmentCounter +"\"]";
|
||||
@@ -391,11 +539,13 @@ public class Sucker {
|
||||
a=htmlTagLowerCase.indexOf("alt=\"")+5;
|
||||
if(a>=5)
|
||||
{
|
||||
b=a+1;
|
||||
while(htmlTagLowerCase.charAt(b)!='\"')
|
||||
b++;
|
||||
String altText=htmlTag.substring(a,b);
|
||||
ret+=altText;
|
||||
b=a;
|
||||
if(htmlTagLowerCase.charAt(b)!='\"') {
|
||||
while(htmlTagLowerCase.charAt(b)!='\"')
|
||||
b++;
|
||||
String altText=htmlTag.substring(a,b);
|
||||
ret+=altText;
|
||||
}
|
||||
}
|
||||
|
||||
ret+="[/img]";
|
||||
@@ -405,14 +555,14 @@ public class Sucker {
|
||||
|
||||
fetchAttachment(imageLink);
|
||||
|
||||
System.out.println("Converted to: "+ret);
|
||||
debugLog("Converted to: "+ret);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
if(importRefs && htmlTagLowerCase.startsWith("<a "))
|
||||
if(htmlTagLowerCase.startsWith("<a "))
|
||||
{
|
||||
System.out.println("Found link tag: "+htmlTag);
|
||||
debugLog("Found link tag: "+htmlTag);
|
||||
int a,b;
|
||||
|
||||
a=htmlTagLowerCase.indexOf("href=\"")+6;
|
||||
@@ -426,16 +576,21 @@ public class Sucker {
|
||||
String schema="web";
|
||||
|
||||
ret += "[link schema=\""+schema+"\" location=\""+link+"\"]";
|
||||
pendingEndLink=true;
|
||||
if(htmlTagLowerCase.endsWith("/>"))
|
||||
ret += "[/link]";
|
||||
else
|
||||
pendingEndLink=true;
|
||||
|
||||
System.out.println("Converted to: "+ret);
|
||||
debugLog("Converted to: "+ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ("</a>".equals(htmlTagLowerCase)) {
|
||||
if (pendingEndLink)
|
||||
if (pendingEndLink) {
|
||||
pendingEndLink=false;
|
||||
return "[/link]";
|
||||
}
|
||||
}
|
||||
|
||||
if("<b>".equals(htmlTagLowerCase))
|
||||
@@ -446,19 +601,65 @@ public class Sucker {
|
||||
return "[i]";
|
||||
if("</i>".equals(htmlTagLowerCase))
|
||||
return "[/i]";
|
||||
if("<em>".equals(htmlTagLowerCase))
|
||||
return "[i]";
|
||||
if("</em>".equals(htmlTagLowerCase))
|
||||
return "[/i]";
|
||||
if("<strong>".equals(htmlTagLowerCase))
|
||||
return "[b]";
|
||||
if("</strong>".equals(htmlTagLowerCase))
|
||||
return "[/b]";
|
||||
if(htmlTagLowerCase.startsWith("<br")) {
|
||||
stripNewlines=true;
|
||||
return "\n";
|
||||
}
|
||||
if("<p>".equals(htmlTagLowerCase))
|
||||
return "\n\n";
|
||||
if("</p>".equals(htmlTagLowerCase))
|
||||
return "";
|
||||
if("<li>".equals(htmlTagLowerCase))
|
||||
return "\n * ";
|
||||
if("</li>".equals(htmlTagLowerCase))
|
||||
return "";
|
||||
if("</br>".equals(htmlTagLowerCase))
|
||||
return "";
|
||||
if(htmlTagLowerCase.startsWith("<table") || "</table>".equals(htmlTagLowerCase)) // emulate table with hr
|
||||
return "[hr][/hr]";
|
||||
|
||||
for(int i=0;i<ignoreTags.length;i++) {
|
||||
String openTag = "<"+ignoreTags[i];
|
||||
String closeTag = "</"+ignoreTags[i];
|
||||
if(htmlTagLowerCase.startsWith(openTag))
|
||||
return "";
|
||||
if(htmlTagLowerCase.startsWith(closeTag))
|
||||
return "";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fetchAttachment(String link) {
|
||||
|
||||
System.out.println("Fetch attachment from: "+link);
|
||||
link=link.replaceAll("&","&");
|
||||
|
||||
String attachmentPath = messagePath+"."+attachmentCounter;
|
||||
link=link.replaceAll("&","&");
|
||||
|
||||
infoLog("Fetch attachment from: "+link);
|
||||
|
||||
File fetched;
|
||||
if(pushToSyndie) {
|
||||
try {
|
||||
// perhaps specify a temp dir?
|
||||
fetched = File.createTempFile("sucker",".attachment");
|
||||
fetched.deleteOnExit();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
tempFiles.add(fetched);
|
||||
} else {
|
||||
String attachmentPath = messagePath+"."+attachmentCounter;
|
||||
fetched = new File(attachmentPath);
|
||||
}
|
||||
int numRetries = 2;
|
||||
File fetched = new File(attachmentPath);
|
||||
// we use eepGet, since it retries and doesn't leak DNS requests like URL does
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), shouldProxy, proxyHost, proxyPortNum,
|
||||
numRetries, fetched.getAbsolutePath(), link);
|
||||
@@ -471,9 +672,46 @@ public class Sucker {
|
||||
fetched.delete();
|
||||
return;
|
||||
}
|
||||
tempFiles.add(fetched);
|
||||
String filename=EepGet.suggestName(link);
|
||||
String contentType = get.getContentType();
|
||||
if(contentType==null)
|
||||
contentType="text/plain";
|
||||
debugLog("successful fetch of filename "+filename);
|
||||
if(fileNames==null) fileNames = new ArrayList();
|
||||
if(fileTypes==null) fileTypes = new ArrayList();
|
||||
if(fileStreams==null) fileStreams = new ArrayList();
|
||||
fileNames.add(filename);
|
||||
fileTypes.add(contentType);
|
||||
try {
|
||||
fileStreams.add(new FileInputStream(fetched));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
attachmentCounter++;
|
||||
}
|
||||
|
||||
private void errorLog(String string) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(string);
|
||||
if(!pushToSyndie)
|
||||
System.out.println(string);
|
||||
}
|
||||
|
||||
private void infoLog(String string) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(string);
|
||||
if(!pushToSyndie)
|
||||
System.out.println(string);
|
||||
}
|
||||
|
||||
private void debugLog(String string) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(string);
|
||||
if(!pushToSyndie)
|
||||
System.out.println(string);
|
||||
}
|
||||
|
||||
private static int findTagLen(String s) {
|
||||
int i;
|
||||
for(i=0;i<s.length();i++)
|
||||
@@ -487,7 +725,6 @@ public class Sucker {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
System.out.println("WTF");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -513,25 +750,11 @@ public class Sucker {
|
||||
return true;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.out.println("sucker --load $urlToFeed \n"
|
||||
+ "--proxyhost <host> \n"
|
||||
+ "--proxyport <port> \n"
|
||||
+ "--importenclosures true \n"
|
||||
+ "--importrefs true \n"
|
||||
+ "--tag feed \n"
|
||||
+ "--outputdir ./sucker_out \n"
|
||||
+ "--exec pushscript.sh OUTPUTDIR UNIQUEID ENTRYTIMESTAMP \n"
|
||||
+ "--history ./sucker.history");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static String sha1(String s) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
@@ -552,7 +775,6 @@ public class Sucker {
|
||||
try {
|
||||
c = in.read();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
@@ -562,7 +784,6 @@ public class Sucker {
|
||||
break;
|
||||
sb.append((char) c);
|
||||
}
|
||||
// TODO Auto-generated method stub
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
105
apps/syndie/java/src/net/i2p/syndie/ThreadNodeImpl.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.syndie.data.BlogURI;
|
||||
import net.i2p.syndie.data.ThreadNode;
|
||||
|
||||
/**
|
||||
* Simple memory intensive (but fast) node impl
|
||||
*
|
||||
*/
|
||||
class ThreadNodeImpl implements ThreadNode {
|
||||
/** write once, never updated once the tree is created */
|
||||
private Collection _recursiveAuthors;
|
||||
/** contains the BlogURI instances */
|
||||
private Collection _recursiveEntries;
|
||||
/** write once, never updated once the tree is created */
|
||||
private List _children;
|
||||
private BlogURI _entry;
|
||||
private ThreadNode _parent;
|
||||
private BlogURI _parentEntry;
|
||||
private Collection _tags;
|
||||
private Collection _recursiveTags;
|
||||
private long _mostRecentPostDate;
|
||||
private Hash _mostRecentPostAuthor;
|
||||
|
||||
public ThreadNodeImpl() {
|
||||
_recursiveAuthors = new HashSet(1);
|
||||
_recursiveEntries = new HashSet(1);
|
||||
_children = new ArrayList(1);
|
||||
_entry = null;
|
||||
_parent = null;
|
||||
_parentEntry = null;
|
||||
_tags = new HashSet();
|
||||
_recursiveTags = new HashSet();
|
||||
_mostRecentPostDate = -1;
|
||||
_mostRecentPostAuthor = null;
|
||||
}
|
||||
|
||||
void setEntry(BlogURI entry) { _entry = entry; }
|
||||
void addAuthor(Hash author) { _recursiveAuthors.add(author); }
|
||||
void addChild(ThreadNodeImpl child) {
|
||||
if (!_children.contains(child))
|
||||
_children.add(child);
|
||||
}
|
||||
void setParent(ThreadNodeImpl parent) { _parent = parent; }
|
||||
void setParentEntry(BlogURI parent) { _parentEntry = parent; }
|
||||
void addTag(String tag) {
|
||||
_tags.add(tag);
|
||||
_recursiveTags.add(tag);
|
||||
}
|
||||
|
||||
void summarizeThread() {
|
||||
_recursiveAuthors.add(_entry.getKeyHash());
|
||||
_recursiveEntries.add(_entry);
|
||||
_mostRecentPostDate = _entry.getEntryId();
|
||||
_mostRecentPostAuthor = _entry.getKeyHash();
|
||||
|
||||
// we need to go through all children (recursively), in case the
|
||||
// tree is out of order (which it shouldn't be, if its built carefully...)
|
||||
for (int i = 0; i < _children.size(); i++) {
|
||||
ThreadNodeImpl node = (ThreadNodeImpl)_children.get(i);
|
||||
node.summarizeThread();
|
||||
if (node.getMostRecentPostDate() > _mostRecentPostDate) {
|
||||
_mostRecentPostDate = node.getMostRecentPostDate();
|
||||
_mostRecentPostAuthor = node.getMostRecentPostAuthor();
|
||||
}
|
||||
_recursiveTags.addAll(node.getRecursiveTags());
|
||||
_recursiveAuthors.addAll(node.getRecursiveAuthors());
|
||||
_recursiveEntries.addAll(node.getRecursiveEntries());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<node><entry>").append(getEntry().toString()).append("</entry>\n");
|
||||
buf.append("<tags>").append(getTags()).append("</tags>\n");
|
||||
buf.append("<mostRecentPostDate>").append(getMostRecentPostDate()).append("</mostRecentPostDate>\n");
|
||||
buf.append("<recursiveTags>").append(getRecursiveTags()).append("</recursiveTags>\n");
|
||||
buf.append("<children>\n");
|
||||
for (int i = 0; i < _children.size(); i++)
|
||||
buf.append(_children.get(i).toString());
|
||||
buf.append("</children>\n");
|
||||
buf.append("</node>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private Collection getRecursiveAuthors() { return _recursiveAuthors; }
|
||||
private Collection getRecursiveEntries() { return _recursiveEntries; }
|
||||
|
||||
// interface-specified methods doing what one would expect...
|
||||
public boolean containsAuthor(Hash author) { return _recursiveAuthors.contains(author); }
|
||||
public boolean containsEntry(BlogURI uri) { return _recursiveEntries.contains(uri); }
|
||||
public ThreadNode getChild(int index) { return (ThreadNode)_children.get(index); }
|
||||
public int getChildCount() { return _children.size(); }
|
||||
public BlogURI getEntry() { return _entry; }
|
||||
public ThreadNode getParent() { return _parent; }
|
||||
public BlogURI getParentEntry() { return _parentEntry; }
|
||||
public boolean containsTag(String tag) { return _tags.contains(tag); }
|
||||
public Collection getTags() { return _tags; }
|
||||
public Collection getRecursiveTags() { return _recursiveTags; }
|
||||
public long getMostRecentPostDate() { return _mostRecentPostDate; }
|
||||
public Hash getMostRecentPostAuthor() { return _mostRecentPostAuthor; }
|
||||
public Iterator getRecursiveAuthorIterator() { return _recursiveAuthors.iterator(); }
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
@@ -11,21 +13,40 @@ public class Updater {
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(Updater.class);
|
||||
private static final Updater _instance = new Updater();
|
||||
private long _lastUpdate;
|
||||
private static boolean _woken;
|
||||
|
||||
public void update() {
|
||||
BlogManager bm = BlogManager.instance();
|
||||
if (_lastUpdate + bm.getUpdateDelay()*60*60*1000 > System.currentTimeMillis()) {
|
||||
return;
|
||||
if (!_woken)
|
||||
return;
|
||||
}
|
||||
_lastUpdate = System.currentTimeMillis();
|
||||
_log.debug("Update started.");
|
||||
String[] archives = bm.getUpdateArchives();
|
||||
for (int i = 0; i < archives.length; i++) {
|
||||
_log.debug("Fetching [" + archives[i] + "]");
|
||||
fetchArchive(archives[i]);
|
||||
_log.debug("Done fetching " + archives[i]);
|
||||
}
|
||||
_log.debug("Done fetching archives");
|
||||
List rssFeeds = bm.getRssFeeds();
|
||||
Iterator iter = rssFeeds.iterator();
|
||||
while(iter.hasNext()) {
|
||||
String args[] = (String[])iter.next();
|
||||
_log.debug("rss feed begin: " + args[0]);
|
||||
Sucker sucker = new Sucker(args);
|
||||
sucker.suck();
|
||||
_log.debug("rss feed end: " + args[0]);
|
||||
}
|
||||
_log.debug("Done with all updating");
|
||||
}
|
||||
|
||||
public void fetchArchive(String archive) {
|
||||
if ( (archive == null) || (archive.trim().length() <= 0) ) {
|
||||
_log.error("Fetch a null archive?" + new Exception("source"));
|
||||
return;
|
||||
}
|
||||
BlogManager bm = BlogManager.instance();
|
||||
User user = new User();
|
||||
RemoteArchiveBean rab = new RemoteArchiveBean();
|
||||
@@ -34,12 +55,13 @@ public class Updater {
|
||||
if (rab.getRemoteIndex() != null) {
|
||||
HashMap parameters = new HashMap();
|
||||
parameters.put("action", new String[] {"Fetch all new entries"});
|
||||
rab.fetchSelectedBulk(user, parameters);
|
||||
rab.fetchSelectedBulk(user, parameters, true);
|
||||
}
|
||||
_log.debug(rab.getStatus());
|
||||
}
|
||||
|
||||
public static void main() {
|
||||
_woken = false;
|
||||
_instance.run();
|
||||
}
|
||||
|
||||
@@ -49,12 +71,15 @@ public class Updater {
|
||||
try {
|
||||
Thread.currentThread().sleep(5*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
|
||||
// creates the default user if necessary
|
||||
BlogManager.instance().getDefaultUser();
|
||||
while (true) {
|
||||
int delay = BlogManager.instance().getUpdateDelay();
|
||||
update();
|
||||
try {
|
||||
synchronized (this) {
|
||||
_woken = false;
|
||||
wait(delay * 60 * 60 * 1000);
|
||||
}
|
||||
} catch (InterruptedException exp) {
|
||||
@@ -65,7 +90,8 @@ public class Updater {
|
||||
|
||||
public static void wakeup() {
|
||||
synchronized (_instance) {
|
||||
_woken = true;
|
||||
_instance.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,27 @@ public class User {
|
||||
private int _torProxyPort;
|
||||
private PetNameDB _petnames;
|
||||
private boolean _importAddresses;
|
||||
private boolean _dataImported;
|
||||
|
||||
static final String PROP_USERHASH = "__userHash";
|
||||
|
||||
|
||||
/**
|
||||
* Ugly hack to fetch the default User instance - this is the default
|
||||
* constructor so it can be used as a bean on the web interface. If
|
||||
* the Syndie instance isn't in single user mode, the default User
|
||||
* is an empty unauthenticated User. If the instance IS in single user
|
||||
* mode, this will contain the logged in 'default' user (creating a new
|
||||
* one as necessary). If you just want to create a User object, use the
|
||||
* new User(I2PAppContext ctx) constructor.
|
||||
*
|
||||
*/
|
||||
public User() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
this(I2PAppContext.getGlobalContext());
|
||||
BlogManager.instance().getDefaultUser(this);
|
||||
}
|
||||
|
||||
public User(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
init();
|
||||
}
|
||||
private void init() {
|
||||
@@ -72,6 +88,7 @@ public class User {
|
||||
_lastMetaEntry = 0;
|
||||
_petnames = new PetNameDB();
|
||||
_importAddresses = false;
|
||||
_dataImported = false;
|
||||
}
|
||||
|
||||
public boolean getAuthenticated() { return _authenticated; }
|
||||
@@ -112,6 +129,29 @@ public class User {
|
||||
init();
|
||||
}
|
||||
|
||||
public void dataImported() { _dataImported = true; }
|
||||
public boolean resetDataImported() {
|
||||
boolean rv = _dataImported;
|
||||
_dataImported = false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public boolean changePassword(String oldPass, String pass0, String pass1) {
|
||||
String curPass = _hashedPassword;
|
||||
Hash curPassHash = _context.sha().calculateHash(DataHelper.getUTF8(oldPass));
|
||||
Hash newPassHash = _context.sha().calculateHash(DataHelper.getUTF8(pass0));
|
||||
if (curPassHash.toBase64().equals(curPass)) {
|
||||
if ( (pass0 != null) && (pass1 != null) && (pass0.equals(pass1)) ) {
|
||||
_hashedPassword = newPassHash.toBase64();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String login(String login, String pass, Properties props) {
|
||||
_username = login;
|
||||
load(props);
|
||||
|
||||
163
apps/syndie/java/src/net/i2p/syndie/WritableThreadIndex.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.SMLParser;
|
||||
import net.i2p.syndie.sml.HTMLRenderer;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class WritableThreadIndex extends ThreadIndex {
|
||||
/** map of child (BlogURI) to parent (BlogURI) */
|
||||
private Map _parents;
|
||||
/** map of entry (BlogURI) to tags (String[]) */
|
||||
private Map _tags;
|
||||
private static final String[] NO_TAGS = new String[0];
|
||||
/** b0rk if the thread seems to go too deep */
|
||||
private static final int MAX_THREAD_DEPTH = 64;
|
||||
|
||||
WritableThreadIndex() {
|
||||
super();
|
||||
_parents = new HashMap();
|
||||
_tags = new TreeMap(new NewestEntryFirstComparator());
|
||||
}
|
||||
|
||||
void addParent(BlogURI parent, BlogURI child) { _parents.put(child, parent); }
|
||||
void addEntry(BlogURI entry, String tags[]) {
|
||||
if (tags == null) tags = NO_TAGS;
|
||||
String oldTags[] = (String[])_tags.put(entry, tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* pull the data added together into threads, and stash them in the
|
||||
* roots, organized chronologically
|
||||
*
|
||||
*/
|
||||
void organizeTree() {
|
||||
Map nodes = new HashMap(_tags.size());
|
||||
for (Iterator iter = _tags.keySet().iterator(); iter.hasNext(); ) {
|
||||
BlogURI entry = (BlogURI)iter.next();
|
||||
String tags[] = (String[])_tags.get(entry);
|
||||
BlogURI parent = (BlogURI)_parents.get(entry);
|
||||
ThreadNodeImpl node = new ThreadNodeImpl();
|
||||
node.setEntry(entry);
|
||||
if (tags != null)
|
||||
for (int i = 0; i < tags.length; i++)
|
||||
node.addTag(tags[i]);
|
||||
if (parent != null)
|
||||
node.setParentEntry(parent);
|
||||
addEntry(entry, node);
|
||||
nodes.put(entry, node);
|
||||
}
|
||||
|
||||
SMLParser parser = new SMLParser(I2PAppContext.getGlobalContext());
|
||||
HeaderReceiver rec = new HeaderReceiver();
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
|
||||
for (Iterator iter = nodes.keySet().iterator(); iter.hasNext(); ) {
|
||||
BlogURI entry = (BlogURI)iter.next();
|
||||
ThreadNodeImpl node = (ThreadNodeImpl)nodes.get(entry);
|
||||
int depth = 0;
|
||||
// climb the tree
|
||||
while (node.getParentEntry() != null) {
|
||||
ThreadNodeImpl parent = (ThreadNodeImpl)nodes.get(node.getParentEntry());
|
||||
if (parent == null) break;
|
||||
|
||||
// if the parent doesn't want replies, only include replies under the tree
|
||||
// if they're written by the same author
|
||||
BlogURI parentURI = parent.getEntry();
|
||||
EntryContainer parentEntry = archive.getEntry(parentURI);
|
||||
if (parentEntry != null) {
|
||||
parser.parse(parentEntry.getEntry().getText(), rec);
|
||||
String refuse = rec.getHeader(HTMLRenderer.HEADER_REFUSE_REPLIES);
|
||||
if ( (refuse != null) && (Boolean.valueOf(refuse).booleanValue()) ) {
|
||||
if (parent.getEntry().getKeyHash().equals(entry.getKeyHash())) {
|
||||
// same author, allow the reply
|
||||
} else {
|
||||
// different author, refuse
|
||||
parent = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.setParent(parent);
|
||||
parent.addChild(node);
|
||||
node = parent;
|
||||
depth++;
|
||||
if (depth > MAX_THREAD_DEPTH)
|
||||
break;
|
||||
}
|
||||
|
||||
node.summarizeThread();
|
||||
}
|
||||
|
||||
// we do this in a second pass, since we need the data built by the
|
||||
// summarizeThread() of a fully constructed tree
|
||||
|
||||
TreeSet roots = new TreeSet(new NewestNodeFirstComparator());
|
||||
for (Iterator iter = nodes.keySet().iterator(); iter.hasNext(); ) {
|
||||
BlogURI entry = (BlogURI)iter.next();
|
||||
ThreadNode node = (ThreadNode)nodes.get(entry);
|
||||
int depth = 0;
|
||||
// climb the tree
|
||||
while (node.getParent() != null)
|
||||
node = node.getParent();
|
||||
|
||||
roots.add(node);
|
||||
}
|
||||
|
||||
// store them, sorted by most recently updated thread first
|
||||
for (Iterator iter = roots.iterator(); iter.hasNext(); )
|
||||
addRoot((ThreadNode)iter.next());
|
||||
|
||||
_parents.clear();
|
||||
_tags.clear();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("<threadIndex>");
|
||||
for (int i = 0; i < getRootCount(); i++) {
|
||||
ThreadNode root = getRoot(i);
|
||||
buf.append(root.toString());
|
||||
}
|
||||
buf.append("</threadIndex>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** sort BlogURI instances with the highest entryId first */
|
||||
private class NewestEntryFirstComparator implements Comparator {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
BlogURI left = (BlogURI)lhs;
|
||||
BlogURI right = (BlogURI)rhs;
|
||||
if (left.getEntryId() > right.getEntryId()) {
|
||||
return -1;
|
||||
} else if (left.getEntryId() == right.getEntryId()) {
|
||||
return DataHelper.compareTo(left.getKeyHash().getData(), right.getKeyHash().getData());
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** sort ThreadNodeImpl instances with the highest entryId first */
|
||||
private class NewestNodeFirstComparator implements Comparator {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
ThreadNodeImpl left = (ThreadNodeImpl)lhs;
|
||||
ThreadNodeImpl right = (ThreadNodeImpl)rhs;
|
||||
long l = left.getMostRecentPostDate();
|
||||
long r = right.getMostRecentPostDate();
|
||||
if (l > r) {
|
||||
return -1;
|
||||
} else if (l == r) {
|
||||
return DataHelper.compareTo(left.getEntry().getKeyHash().getData(), right.getEntry().getKeyHash().getData());
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ public class ArchiveIndex {
|
||||
/** parent message to a set of replies, ordered with the oldest first */
|
||||
protected Map _replies;
|
||||
protected Properties _headers;
|
||||
private ThreadIndex _threadedIndex;
|
||||
|
||||
public ArchiveIndex() {
|
||||
this(I2PAppContext.getGlobalContext(), false);
|
||||
@@ -48,6 +49,7 @@ public class ArchiveIndex {
|
||||
_headers = new Properties();
|
||||
_replies = Collections.synchronizedMap(new HashMap());
|
||||
_generatedOn = -1;
|
||||
_threadedIndex = null;
|
||||
if (shouldLoad)
|
||||
setIsLocal("true");
|
||||
}
|
||||
@@ -61,6 +63,8 @@ public class ArchiveIndex {
|
||||
public long getTotalSize() { return _totalSize; }
|
||||
public long getNewSize() { return _newSize; }
|
||||
public long getGeneratedOn() { return _generatedOn; }
|
||||
public ThreadIndex getThreadedIndex() { return _threadedIndex; }
|
||||
public void setThreadedIndex(ThreadIndex index) { _threadedIndex = index; }
|
||||
|
||||
public String getNewSizeStr() {
|
||||
if (_newSize < 1024) return _newSize + "";
|
||||
|
||||
@@ -55,6 +55,7 @@ public class BlogInfo {
|
||||
public static final String SIGNATURE = "Signature";
|
||||
public static final String NAME = "Name";
|
||||
public static final String DESCRIPTION = "Description";
|
||||
public static final String CONTACT_URL = "ContactURL";
|
||||
public static final String EDITION = "Edition";
|
||||
|
||||
public void load(InputStream in) throws IOException {
|
||||
|
||||
@@ -74,7 +74,9 @@ public class BlogURI {
|
||||
DataHelper.eq(_blogHash, ((BlogURI)obj)._blogHash);
|
||||
}
|
||||
public int hashCode() {
|
||||
int rv = (int)_entryId;
|
||||
int rv = (int)((_entryId >>> 32) & 0x7FFFFFFF);
|
||||
rv += (_entryId & 0x7FFFFFFF);
|
||||
|
||||
if (_blogHash != null)
|
||||
rv += _blogHash.hashCode();
|
||||
return rv;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.client.naming.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class FilteredThreadIndex extends ThreadIndex {
|
||||
private User _user;
|
||||
private Archive _archive;
|
||||
private ThreadIndex _baseIndex;
|
||||
private Collection _filteredTags;
|
||||
private List _roots;
|
||||
private List _ignoredAuthors;
|
||||
private Collection _filteredAuthors;
|
||||
|
||||
public static final String GROUP_FAVORITE = "Favorite";
|
||||
public static final String GROUP_IGNORE = "Ignore";
|
||||
|
||||
public FilteredThreadIndex(User user, Archive archive, Collection tags, Collection authors) {
|
||||
super();
|
||||
_user = user;
|
||||
_archive = archive;
|
||||
_baseIndex = _archive.getIndex().getThreadedIndex();
|
||||
_filteredTags = tags;
|
||||
if (_filteredTags == null)
|
||||
_filteredTags = Collections.EMPTY_SET;
|
||||
_filteredAuthors = authors;
|
||||
if (_filteredAuthors == null)
|
||||
_filteredAuthors = Collections.EMPTY_SET;
|
||||
|
||||
_ignoredAuthors = new ArrayList();
|
||||
for (Iterator iter = user.getPetNameDB().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = (PetName)iter.next();
|
||||
if (pn.isMember(GROUP_IGNORE)) {
|
||||
try {
|
||||
Hash h = new Hash();
|
||||
h.fromBase64(pn.getLocation());
|
||||
_ignoredAuthors.add(h);
|
||||
} catch (DataFormatException dfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filter();
|
||||
}
|
||||
|
||||
private void filter() {
|
||||
_roots = new ArrayList(_baseIndex.getRootCount());
|
||||
for (int i = 0; i < _baseIndex.getRootCount(); i++) {
|
||||
ThreadNode node = _baseIndex.getRoot(i);
|
||||
if (!isIgnored(node, _ignoredAuthors, _filteredTags, _filteredAuthors))
|
||||
_roots.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isIgnored(ThreadNode node, List ignoredAuthors, Collection requestedTags, Collection filteredAuthors) {
|
||||
if (filteredAuthors.size() <= 0) {
|
||||
boolean allAuthorsIgnored = true;
|
||||
for (Iterator iter = node.getRecursiveAuthorIterator(); iter.hasNext(); ) {
|
||||
Hash author = (Hash)iter.next();
|
||||
if (!ignoredAuthors.contains(author)) {
|
||||
allAuthorsIgnored = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (allAuthorsIgnored) && (ignoredAuthors.size() > 0) )
|
||||
return true;
|
||||
} else {
|
||||
boolean filteredAuthorMatches = false;
|
||||
for (Iterator iter = filteredAuthors.iterator(); iter.hasNext(); ) {
|
||||
Hash author = (Hash)iter.next();
|
||||
if (node.containsAuthor(author)) {
|
||||
filteredAuthorMatches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!filteredAuthorMatches)
|
||||
return true;
|
||||
}
|
||||
|
||||
// ok, author checking passed, so only ignore the thread if tags were specified and the
|
||||
// thread doesn't contain that tag
|
||||
|
||||
if (requestedTags.size() > 0) {
|
||||
Collection nodeTags = node.getRecursiveTags();
|
||||
for (Iterator iter = requestedTags.iterator(); iter.hasNext(); )
|
||||
if (nodeTags.contains(iter.next()))
|
||||
return false;
|
||||
// authors we aren't ignoring have posted in the thread, but the user is filtering
|
||||
// posts by tags, and this thread doesn't include any of those tags
|
||||
return true;
|
||||
} else {
|
||||
// we aren't filtering by tags, and we haven't been refused by the author
|
||||
// filtering
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getRootCount() { return _roots.size(); }
|
||||
public ThreadNode getRoot(int index) { return (ThreadNode)_roots.get(index); }
|
||||
public ThreadNode getNode(BlogURI uri) { return _baseIndex.getNode(uri); }
|
||||
public Collection getFilteredTags() { return _filteredTags; }
|
||||
public Collection getFilteredAuthors() { return _filteredAuthors; }
|
||||
}
|
||||
49
apps/syndie/java/src/net/i2p/syndie/data/ThreadIndex.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* List of threads, ordered with the most recently updated thread first.
|
||||
* Each node in the tree summarizes everything underneath it as well.
|
||||
*
|
||||
*/
|
||||
public class ThreadIndex {
|
||||
/** ordered list of threads, with most recent first */
|
||||
private List _roots;
|
||||
/** map of BlogURI to ThreadNode */
|
||||
private Map _nodes;
|
||||
|
||||
protected ThreadIndex() {
|
||||
// no need to synchronize, since the thread index doesn't change after
|
||||
// its first built
|
||||
_roots = new ArrayList();
|
||||
_nodes = new HashMap(64);
|
||||
}
|
||||
|
||||
public int getRootCount() { return _roots.size(); }
|
||||
public ThreadNode getRoot(int index) { return (ThreadNode)_roots.get(index); }
|
||||
public ThreadNode getNode(BlogURI uri) { return (ThreadNode)_nodes.get(uri); }
|
||||
/**
|
||||
* get the root of the thread that the given uri is located in, or -1.
|
||||
* The implementation depends only on getRoot/getNode/getRootCount and not on the
|
||||
* data structures, so should be safe for subclasses who adjust those methods
|
||||
*
|
||||
*/
|
||||
public int getRoot(BlogURI uri) {
|
||||
ThreadNode node = getNode(uri);
|
||||
if (node == null) return -1;
|
||||
while (node.getParent() != null)
|
||||
node = node.getParent();
|
||||
for (int i = 0; i < getRootCount(); i++) {
|
||||
ThreadNode cur = getRoot(i);
|
||||
if (cur.equals(node))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** call this in the right order - most recently updated thread first */
|
||||
protected void addRoot(ThreadNode node) { _roots.add(node); }
|
||||
/** invocation order here doesn't matter */
|
||||
protected void addEntry(BlogURI uri, ThreadNode node) { _nodes.put(uri, node); }
|
||||
}
|
||||
34
apps/syndie/java/src/net/i2p/syndie/data/ThreadNode.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.data.Hash;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface ThreadNode {
|
||||
/** current post */
|
||||
public BlogURI getEntry();
|
||||
/** how many direct replies there are to the current entry */
|
||||
public int getChildCount();
|
||||
/** the given direct reply */
|
||||
public ThreadNode getChild(int index);
|
||||
/** parent this is actually a reply to */
|
||||
public BlogURI getParentEntry();
|
||||
/** parent in the tree, maybe not a direct parent, but the closest one */
|
||||
public ThreadNode getParent();
|
||||
/** true if this entry, or any child, is written by the given author */
|
||||
public boolean containsAuthor(Hash author);
|
||||
/** true if this node, or any child, includes the given URI */
|
||||
public boolean containsEntry(BlogURI uri);
|
||||
/** list of tags (String) of this node only */
|
||||
public Collection getTags();
|
||||
/** list of tags (String) of this node or any children in the tree */
|
||||
public Collection getRecursiveTags();
|
||||
/** date of the most recent post, recursive */
|
||||
public long getMostRecentPostDate();
|
||||
/** author of the most recent post, recurisve */
|
||||
public Hash getMostRecentPostAuthor();
|
||||
/** walk across the authors of the entire thread */
|
||||
public Iterator getRecursiveAuthorIterator();
|
||||
}
|
||||
@@ -25,6 +25,7 @@ public class TransparentArchiveIndex extends ArchiveIndex {
|
||||
public long getTotalSize() { return index().getTotalSize(); }
|
||||
public long getNewSize() { return index().getNewSize(); }
|
||||
public long getGeneratedOn() { return index().getGeneratedOn(); }
|
||||
public ThreadIndex getThreadedIndex() { return index().getThreadedIndex(); }
|
||||
|
||||
public String getNewSizeStr() { return index().getNewSizeStr(); }
|
||||
public String getTotalSizeStr() { return index().getTotalSizeStr(); }
|
||||
|
||||
@@ -112,13 +112,13 @@ public class HTMLPreviewRenderer extends HTMLRenderer {
|
||||
} else {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailAddrLink")).append(" href=\"addresses.jsp?");
|
||||
if (a.schema != null)
|
||||
_postBodyBuffer.append("network=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NET).append("=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
if (a.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeTagParam(a.location)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_LOC).append("=").append(sanitizeTagParam(a.location)).append('&');
|
||||
if (a.name != null)
|
||||
_postBodyBuffer.append("name=").append(sanitizeTagParam(a.name)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NAME).append("=").append(sanitizeTagParam(a.name)).append('&');
|
||||
if (a.protocol != null)
|
||||
_postBodyBuffer.append("protocol=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_PROTO).append("=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,11 +400,15 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
if (location != null) {
|
||||
_bodyBuffer.append(" at ");
|
||||
SafeURL surl = new SafeURL(locationSchema + "://" + location);
|
||||
_bodyBuffer.append("<a ").append(getClass("archiveSummaryLink")).append(" href=\"").append(getArchiveURL(null, surl));
|
||||
_bodyBuffer.append("\">").append(sanitizeString(surl.toString())).append("</a>");
|
||||
if (BlogManager.instance().authorizeRemote(_user)) {
|
||||
_bodyBuffer.append("<a ").append(getClass("archiveSummaryLink")).append(" href=\"").append(getArchiveURL(null, surl));
|
||||
_bodyBuffer.append("\">").append(sanitizeString(surl.toString())).append("</a>");
|
||||
} else {
|
||||
_bodyBuffer.append(sanitizeString(surl.getLocation()));
|
||||
}
|
||||
if (_user.getAuthenticated()) {
|
||||
_bodyBuffer.append(" <a ").append(getClass("archiveBookmarkLink")).append(" href=\"");
|
||||
_bodyBuffer.append(getBookmarkURL(sanitizeString(name), surl.getLocation(), surl.getSchema(), "syndiearchive"));
|
||||
_bodyBuffer.append(getBookmarkURL(sanitizeString(name), surl.getLocation(), surl.getSchema(), AddressesServlet.PROTO_ARCHIVE));
|
||||
_bodyBuffer.append("\">bookmark it</a>");
|
||||
}
|
||||
}
|
||||
@@ -492,13 +496,13 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_log.debug("Receiving address [" + location + "]");
|
||||
_bodyBuffer.append("<a ").append(getClass("addrAdd")).append(" href=\"addresses.jsp?");
|
||||
if (schema != null)
|
||||
_bodyBuffer.append("network=").append(sanitizeTagParam(schema)).append('&');
|
||||
_bodyBuffer.append(AddressesServlet.PARAM_NET).append('=').append(sanitizeTagParam(schema)).append('&');
|
||||
if (name != null)
|
||||
_bodyBuffer.append("name=").append(sanitizeTagParam(name)).append('&');
|
||||
_bodyBuffer.append(AddressesServlet.PARAM_NAME).append('=').append(sanitizeTagParam(name)).append('&');
|
||||
if (protocol != null)
|
||||
_bodyBuffer.append("protocol=").append(sanitizeTagParam(protocol)).append('&');
|
||||
_bodyBuffer.append(AddressesServlet.PARAM_PROTO).append('=').append(sanitizeTagParam(protocol)).append('&');
|
||||
if (location != null)
|
||||
_bodyBuffer.append("location=").append(sanitizeTagParam(location));
|
||||
_bodyBuffer.append(AddressesServlet.PARAM_LOC).append('=').append(sanitizeTagParam(location));
|
||||
_bodyBuffer.append("\">").append(sanitizeString(anchorText)).append("</a>");
|
||||
}
|
||||
}
|
||||
@@ -514,7 +518,10 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_bodyBuffer.append(getSpan("attachmentSummary")).append(" (");
|
||||
_bodyBuffer.append(getSpan("attachmentSummarySize")).append(attachments[id].getDataLength()/1024).append("KB</span>, ");
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryName")).append(" \"").append(sanitizeString(attachments[id].getName())).append("\"</span>, ");
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryDesc")).append(" \"").append(sanitizeString(attachments[id].getDescription())).append("\"</span>, ");
|
||||
String descr = attachments[id].getDescription();
|
||||
if ( (descr != null) && (descr.trim().length() > 0) ) {
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryDesc")).append(" \"").append(sanitizeString(descr.trim())).append("\"</span>, ");
|
||||
}
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryType")).append(sanitizeString(attachments[id].getMimeType())).append("</span>)</span>");
|
||||
}
|
||||
}
|
||||
@@ -571,7 +578,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) )
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summParent")).append(" href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a>\n");
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summParent")).append(" href=\"threads.jsp?").append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(sanitizeTagParam(inReplyTo)).append("\">(view parent)</a>\n");
|
||||
|
||||
_postBodyBuffer.append("</span></td></tr>\n");
|
||||
_postBodyBuffer.append("<!-- end of the post summary -->\n");
|
||||
@@ -655,13 +662,13 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
} else {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailAddrLink")).append(" href=\"addresses.jsp?");
|
||||
if (a.schema != null)
|
||||
_postBodyBuffer.append("network=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NET).append('=').append(sanitizeTagParam(a.schema)).append('&');
|
||||
if (a.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeTagParam(a.location)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_LOC).append('=').append(sanitizeTagParam(a.location)).append('&');
|
||||
if (a.name != null)
|
||||
_postBodyBuffer.append("name=").append(sanitizeTagParam(a.name)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NAME).append('=').append(sanitizeTagParam(a.name)).append('&');
|
||||
if (a.protocol != null)
|
||||
_postBodyBuffer.append("protocol=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_PROTO).append('=').append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
}
|
||||
}
|
||||
@@ -678,7 +685,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_postBodyBuffer.append(": ").append(getSpan("summDetailArchiveDesc")).append(sanitizeString(a.description)).append("</span>");
|
||||
if (null == _user.getPetNameDB().getByLocation(a.location)) {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveBookmark")).append(" href=\"");
|
||||
_postBodyBuffer.append(getBookmarkURL(a.name, a.location, a.locationSchema, "syndiearchive"));
|
||||
_postBodyBuffer.append(getBookmarkURL(a.name, a.location, a.locationSchema, AddressesServlet.PROTO_ARCHIVE));
|
||||
_postBodyBuffer.append("\">bookmark it</a>");
|
||||
}
|
||||
}
|
||||
@@ -712,7 +719,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) ) {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailParent")).append(" href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a><br />\n");
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailParent")).append(" href=\"threads.jsp?").append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(sanitizeTagParam(inReplyTo)).append("\">(view parent)</a>\n");
|
||||
}
|
||||
|
||||
_postBodyBuffer.append("</td>\n</form>\n</tr>\n");
|
||||
@@ -755,6 +762,10 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
public static final String HEADER_STYLE = "Style";
|
||||
public static final String HEADER_PETNAME = "PetName";
|
||||
public static final String HEADER_TAGS = "Tags";
|
||||
/** if set to true, don't display the message in the same thread, though keep a parent reference */
|
||||
public static final String HEADER_FORCE_NEW_THREAD = "ForceNewThread";
|
||||
/** if set to true, don't let anyone else reply in the same thread (but let the original author reply) */
|
||||
public static final String HEADER_REFUSE_REPLIES = "RefuseReplies";
|
||||
|
||||
private void renderSubjectCell() {
|
||||
_preBodyBuffer.append("<form action=\"index.jsp\">");
|
||||
@@ -880,7 +891,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
}
|
||||
|
||||
private final SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.UK);
|
||||
private final String getEntryDate(long when) {
|
||||
public final String getEntryDate(long when) {
|
||||
synchronized (_dateFormat) {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(when));
|
||||
@@ -896,7 +907,9 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
}
|
||||
|
||||
public static final String sanitizeString(String str) { return sanitizeString(str, true); }
|
||||
public static final String sanitizeString(String str, boolean allowNL) {
|
||||
public static final String sanitizeString(String str, int maxLen) { return sanitizeString(str, true, maxLen); }
|
||||
public static final String sanitizeString(String str, boolean allowNL) { return sanitizeString(str, allowNL, -1); }
|
||||
public static final String sanitizeString(String str, boolean allowNL, int maxLen) {
|
||||
if (str == null) return null;
|
||||
boolean unsafe = false;
|
||||
unsafe = unsafe || str.indexOf('<') >= 0;
|
||||
@@ -906,21 +919,24 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
unsafe = unsafe || str.indexOf('\r') >= 0;
|
||||
unsafe = unsafe || str.indexOf('\f') >= 0;
|
||||
}
|
||||
if (!unsafe) return str;
|
||||
|
||||
//str = str.replace('<', '_'); // this should be <
|
||||
//str = str.replace('>', '-'); // this should be >
|
||||
str = str.replaceAll("<", "<");
|
||||
str = str.replaceAll(">", ">");
|
||||
if (!allowNL) {
|
||||
//str = str.replace('\n', ' ');
|
||||
//str = str.replace('\r', ' ');
|
||||
//str = str.replace('\f', ' ');
|
||||
str = str.replaceAll("\n", "<br />"); // no class
|
||||
str = str.replaceAll("\r", "<br />"); // no class
|
||||
str = str.replaceAll("\f", "<br />"); // no class
|
||||
if (unsafe) {
|
||||
//str = str.replace('<', '_'); // this should be <
|
||||
//str = str.replace('>', '-'); // this should be >
|
||||
str = str.replaceAll("<", "<");
|
||||
str = str.replaceAll(">", ">");
|
||||
if (!allowNL) {
|
||||
//str = str.replace('\n', ' ');
|
||||
//str = str.replace('\r', ' ');
|
||||
//str = str.replace('\f', ' ');
|
||||
str = str.replaceAll("\n", "<br />"); // no class
|
||||
str = str.replaceAll("\r", "<br />"); // no class
|
||||
str = str.replaceAll("\f", "<br />"); // no class
|
||||
}
|
||||
}
|
||||
return str;
|
||||
if ( (maxLen > 0) && (str.length() > maxLen) )
|
||||
return str.substring(0, maxLen) + "...";
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
public static final String sanitizeURL(String str) {
|
||||
@@ -971,11 +987,10 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
protected String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : false); }
|
||||
protected String getEntryURL(boolean showImages) {
|
||||
if (_entry == null) return "unknown";
|
||||
return "index.jsp?" + ArchiveViewerBean.PARAM_BLOG + "=" +
|
||||
Base64.encode(_entry.getURI().getKeyHash().getData()) +
|
||||
"&" + ArchiveViewerBean.PARAM_ENTRY + "=" + _entry.getURI().getEntryId() +
|
||||
"&" + ArchiveViewerBean.PARAM_SHOW_IMAGES + (showImages ? "=true" : "=false") +
|
||||
"&" + ArchiveViewerBean.PARAM_EXPAND_ENTRIES + "=true";
|
||||
return "threads.jsp?" + ThreadedHTMLRenderer.PARAM_AUTHOR + '=' +
|
||||
Base64.encode(_entry.getURI().getKeyHash().getData()) + '&' +
|
||||
ThreadedHTMLRenderer.PARAM_VIEW_POST + '=' + _entry.getURI().getKeyHash().toBase64() + '/' +
|
||||
_entry.getURI().getEntryId();
|
||||
}
|
||||
|
||||
protected String getAttachmentURLBase() { return "viewattachment.jsp"; }
|
||||
@@ -992,19 +1007,19 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
if (_entry == null) return "unknown";
|
||||
return getMetadataURL(_entry.getURI().getKeyHash());
|
||||
}
|
||||
public static String getMetadataURL(Hash blog) {
|
||||
public String getMetadataURL(Hash blog) {
|
||||
return "viewmetadata.jsp?" + ArchiveViewerBean.PARAM_BLOG + "=" +
|
||||
Base64.encode(blog.getData());
|
||||
}
|
||||
|
||||
public static String getPostURL(Hash blog) {
|
||||
public String getPostURL(Hash blog) {
|
||||
return "post.jsp?" + ArchiveViewerBean.PARAM_BLOG + "=" + Base64.encode(blog.getData());
|
||||
}
|
||||
public String getPostURL(Hash blog, boolean asReply, String subject, String tags) {
|
||||
if (asReply && _entry != null) {
|
||||
StringBuffer rv = new StringBuffer(128);
|
||||
rv.append("post.jsp?").append(ArchiveViewerBean.PARAM_BLOG).append("=").append(Base64.encode(blog.getData()));
|
||||
rv.append('&').append(ArchiveViewerBean.PARAM_IN_REPLY_TO).append('=');
|
||||
rv.append('&').append(PostServlet.PARAM_PARENT).append('=');
|
||||
rv.append(Base64.encode("entry://" + _entry.getURI().getKeyHash().toBase64() + "/" + _entry.getURI().getEntryId()));
|
||||
if (subject != null)
|
||||
rv.append('&').append(ArchiveViewerBean.PARAM_SUBJECT).append('=').append(Base64.encode(subject));
|
||||
@@ -1016,55 +1031,56 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
return getPostURL(blog);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPageURL(String selector) { return getPageURL(_user, selector); }
|
||||
public static String getPageURL(User user, String selector) { return getPageURL(user, selector, -1, -1); }
|
||||
public static String getPageURL(User user, String selector, int numPerPage, int pageNum) {
|
||||
|
||||
/**
|
||||
* entry may take the form of "base64/messageId", "entry://base64/messageId", or "blog://base64/messageId"
|
||||
*
|
||||
*/
|
||||
public String getPageURL(String entry) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("index.jsp?");
|
||||
buf.append("selector=").append(sanitizeTagParam(selector)).append("&");
|
||||
if ( (pageNum >= 0) && (numPerPage > 0) ) {
|
||||
buf.append(ArchiveViewerBean.PARAM_PAGE_NUMBER).append('=').append(pageNum).append('&');
|
||||
buf.append(ArchiveViewerBean.PARAM_NUM_PER_PAGE).append('=').append(numPerPage).append('&');
|
||||
buf.append("threads.jsp?");
|
||||
if (entry != null) {
|
||||
if (entry.startsWith("entry://"))
|
||||
entry = entry.substring("entry://".length());
|
||||
else if (entry.startsWith("blog://"))
|
||||
entry = entry.substring("blog://".length());
|
||||
if (entry.length() > 0) {
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(entry).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=').append(entry).append('&');
|
||||
}
|
||||
}
|
||||
buf.append(ArchiveViewerBean.PARAM_EXPAND_ENTRIES).append('=').append(user.getShowExpanded()).append('&');
|
||||
buf.append(ArchiveViewerBean.PARAM_SHOW_IMAGES).append('=').append(user.getShowImages()).append('&');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getPageURL(Hash blog, String tag, long entryId, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
|
||||
|
||||
public String getPageURL(Hash blog, String tag, long entryId, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
|
||||
return getPageURL(blog, tag, entryId, null, numPerPage, pageNum, expandEntries, showImages);
|
||||
}
|
||||
public static String getPageURL(Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
|
||||
public String getPageURL(Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("index.jsp?");
|
||||
buf.append("threads.jsp?");
|
||||
if (blog != null)
|
||||
buf.append(ArchiveViewerBean.PARAM_BLOG).append('=').append(Base64.encode(blog.getData())).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(blog.toBase64()).append('&');
|
||||
if (tag != null)
|
||||
buf.append(ArchiveViewerBean.PARAM_TAG).append('=').append(Base64.encode(DataHelper.getUTF8(tag))).append('&');
|
||||
if (entryId >= 0)
|
||||
buf.append(ArchiveViewerBean.PARAM_ENTRY).append('=').append(entryId).append('&');
|
||||
if (group != null)
|
||||
buf.append(ArchiveViewerBean.PARAM_GROUP).append('=').append(Base64.encode(DataHelper.getUTF8(group))).append('&');
|
||||
if ( (pageNum >= 0) && (numPerPage > 0) ) {
|
||||
buf.append(ArchiveViewerBean.PARAM_PAGE_NUMBER).append('=').append(pageNum).append('&');
|
||||
buf.append(ArchiveViewerBean.PARAM_NUM_PER_PAGE).append('=').append(numPerPage).append('&');
|
||||
}
|
||||
buf.append(ArchiveViewerBean.PARAM_EXPAND_ENTRIES).append('=').append(expandEntries).append('&');
|
||||
buf.append(ArchiveViewerBean.PARAM_SHOW_IMAGES).append('=').append(showImages).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(sanitizeTagParam(tag)).append('&');
|
||||
if (entryId >= 0) {
|
||||
String entry = blog.toBase64() + '/' + entryId;
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(entry).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=').append(entry).append('&');
|
||||
}
|
||||
if ( (pageNum >= 0) && (numPerPage > 0) )
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(pageNum*numPerPage).append('&');
|
||||
return buf.toString();
|
||||
}
|
||||
public static String getArchiveURL(Hash blog, SafeURL archiveLocation) {
|
||||
return "remote.jsp?"
|
||||
public String getArchiveURL(Hash blog, SafeURL archiveLocation) {
|
||||
return "syndicate.jsp?"
|
||||
//+ "action=Continue..." // should this be the case?
|
||||
+ "&schema=" + sanitizeTagParam(archiveLocation.getSchema())
|
||||
+ "&location=" + sanitizeTagParam(archiveLocation.getLocation());
|
||||
+ "&" + SyndicateServlet.PARAM_SCHEMA + "=" + sanitizeTagParam(archiveLocation.getSchema())
|
||||
+ "&" + SyndicateServlet.PARAM_LOCATION + "=" + sanitizeTagParam(archiveLocation.getLocation());
|
||||
}
|
||||
public static String getBookmarkURL(String name, String location, String schema, String protocol) {
|
||||
return "addresses.jsp?name=" + sanitizeTagParam(name)
|
||||
+ "&network=" + sanitizeTagParam(schema)
|
||||
+ "&protocol=" + sanitizeTagParam(protocol)
|
||||
+ "&location=" + sanitizeTagParam(location);
|
||||
|
||||
public String getBookmarkURL(String name, String location, String schema, String protocol) {
|
||||
return "addresses.jsp?" + AddressesServlet.PARAM_NAME + '=' + sanitizeTagParam(name)
|
||||
+ "&" + AddressesServlet.PARAM_NET + '=' + sanitizeTagParam(schema)
|
||||
+ "&" + AddressesServlet.PARAM_PROTO + '=' + sanitizeTagParam(protocol)
|
||||
+ "&" + AddressesServlet.PARAM_LOC + '=' + sanitizeTagParam(location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.i2p.client.naming.PetName;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.web.AddressesServlet;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -261,10 +262,10 @@ public class RSSRenderer extends HTMLRenderer {
|
||||
pn = _user.getPetNameDB().getByLocation(a.location);
|
||||
if (pn == null) {
|
||||
StringBuffer url = new StringBuffer(128);
|
||||
url.append("addresses.jsp?network=");
|
||||
url.append(sanitizeTagParam(a.schema)).append("&location=");
|
||||
url.append(sanitizeTagParam(a.location)).append("&name=");
|
||||
url.append(sanitizeTagParam(a.name)).append("&protocol=");
|
||||
url.append("addresses.jsp?").append(AddressesServlet.PARAM_NAME).append('=');
|
||||
url.append(sanitizeTagParam(a.schema)).append("&").append(AddressesServlet.PARAM_LOC).append("=");
|
||||
url.append(sanitizeTagParam(a.location)).append("&").append(AddressesServlet.PARAM_NAME).append("=");
|
||||
url.append(sanitizeTagParam(a.name)).append("&").append(AddressesServlet.PARAM_PROTO).append("=");
|
||||
url.append(sanitizeTagParam(a.protocol));
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"address\" />\n");
|
||||
}
|
||||
|
||||
@@ -371,10 +371,15 @@ public class SMLParser {
|
||||
valStart = off;
|
||||
} else {
|
||||
valEnd = off;
|
||||
|
||||
String name = source.substring(nameStart, nameEnd);
|
||||
String val = source.substring(valStart+1, valEnd);
|
||||
rv.put(name.trim(), val.trim());
|
||||
|
||||
if ( ( nameStart >= 0 ) &&
|
||||
( nameEnd >= 0 ) &&
|
||||
( valStart >= 0 ) &&
|
||||
( valEnd >= 0 )) {
|
||||
String name = source.substring(nameStart, nameEnd);
|
||||
String val = source.substring(valStart+1, valEnd);
|
||||
rv.put(name.trim(), val.trim());
|
||||
}
|
||||
nameStart = -1;
|
||||
nameEnd = -1;
|
||||
valStart = -1;
|
||||
@@ -450,6 +455,7 @@ public class SMLParser {
|
||||
|
||||
test("A: B\n\n[b]This[/b] is [i]special[/i][cut]why?[/cut][u]because I say so[/u].\neven if you dont care");
|
||||
test("A: B\n\nHi\n[pre]>foo&bar<>blah!blah\nblah\nblah[/pre]foo![pre]bar[/pre]");
|
||||
//(openTagEnd seems wrong) test("A: B\n\n[link schema=\"web\" location=\"http://w.i2p?i2paddr...\"] Try it [[i2p]] [/link]");
|
||||
}
|
||||
private static void test(String rawSML) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
package net.i2p.syndie.sml;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetName;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.web.*;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ThreadedHTMLRenderer extends HTMLRenderer {
|
||||
private Log _log;
|
||||
private String _baseURI;
|
||||
private boolean _inlineReply;
|
||||
|
||||
public ThreadedHTMLRenderer(I2PAppContext ctx) {
|
||||
super(ctx);
|
||||
_log = ctx.logManager().getLog(ThreadedHTMLRenderer.class);
|
||||
}
|
||||
|
||||
/** what, if any, post should be rendered */
|
||||
public static final String PARAM_VIEW_POST = "post";
|
||||
/** what, if any, thread should be rendered in its entirety */
|
||||
public static final String PARAM_VIEW_THREAD = "thread";
|
||||
/** what post should be visible in the nav tree */
|
||||
public static final String PARAM_VISIBLE = "visible";
|
||||
public static final String PARAM_ADD_TO_GROUP_LOCATION = "addLocation";
|
||||
public static final String PARAM_ADD_TO_GROUP_NAME = "addGroup";
|
||||
/** name of the bookmarked entry to remove */
|
||||
public static final String PARAM_REMOVE_FROM_GROUP_NAME = "removeName";
|
||||
/** group to remove from the bookmarked entry, or if blank, remove the entry itself */
|
||||
public static final String PARAM_REMOVE_FROM_GROUP = "removeGroup";
|
||||
/** index into the nav tree to start displaying */
|
||||
public static final String PARAM_OFFSET = "offset";
|
||||
public static final String PARAM_TAGS = "tags";
|
||||
public static final String PARAM_AUTHOR = "author";
|
||||
// parameters for editing one's profile
|
||||
public static final String PARAM_PROFILE_NAME = "profileName";
|
||||
public static final String PARAM_PROFILE_DESC = "profileDesc";
|
||||
public static final String PARAM_PROFILE_URL = "profileURL";
|
||||
public static final String PARAM_PROFILE_OTHER = "profileOther";
|
||||
|
||||
public static String getFilterByTagLink(String uri, ThreadNode node, User user, String tag, String author) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri).append('?');
|
||||
if (node != null) {
|
||||
buf.append(PARAM_VIEW_POST).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
}
|
||||
|
||||
if (!empty(tag))
|
||||
buf.append(PARAM_TAGS).append('=').append(tag).append('&');
|
||||
|
||||
if (!empty(author))
|
||||
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getNavLink(String uri, String viewPost, String viewThread, String tags, String author, int offset) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
buf.append('?');
|
||||
if (!empty(viewPost))
|
||||
buf.append(PARAM_VIEW_POST).append('=').append(viewPost).append('&');
|
||||
else if (!empty(viewThread))
|
||||
buf.append(PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(author))
|
||||
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
|
||||
buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getViewPostLink(String uri, ThreadNode node, User user, boolean isPermalink,
|
||||
String offset, String tags, String author) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
if (node.getChildCount() > 0) {
|
||||
buf.append('?').append(PARAM_VISIBLE).append('=');
|
||||
ThreadNode child = node.getChild(0);
|
||||
buf.append(child.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(child.getEntry().getEntryId()).append('&');
|
||||
} else {
|
||||
buf.append('?').append(PARAM_VISIBLE).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
}
|
||||
buf.append(PARAM_VIEW_POST).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
|
||||
if (!isPermalink) {
|
||||
if (!empty(offset))
|
||||
buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
if (!empty(tags))
|
||||
buf.append(PARAM_TAGS).append('=').append(tags).append('&');
|
||||
if (!empty(author))
|
||||
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private static final boolean empty(String val) { return (val == null) || (val.trim().length() <= 0); }
|
||||
|
||||
/**
|
||||
* @param replyHiddenFields HTML of hidden input fields necessary for the reply form to be honored
|
||||
*/
|
||||
public void render(User user, Writer out, Archive archive, BlogURI post,
|
||||
boolean inlineReply, ThreadIndex index, String baseURI, String replyHiddenFields,
|
||||
String offset, String requestTags, String filteredAuthor) throws IOException {
|
||||
EntryContainer entry = archive.getEntry(post);
|
||||
if (entry == null) return;
|
||||
_entry = entry;
|
||||
|
||||
_baseURI = baseURI;
|
||||
_user = user;
|
||||
_out = out;
|
||||
_archive = archive;
|
||||
_cutBody = false;
|
||||
_showImages = true;
|
||||
_inlineReply = inlineReply;
|
||||
_headers = new HashMap();
|
||||
_bodyBuffer = new StringBuffer(1024);
|
||||
_postBodyBuffer = new StringBuffer(1024);
|
||||
_addresses = new ArrayList();
|
||||
_links = new ArrayList();
|
||||
_blogs = new ArrayList();
|
||||
_archives = new ArrayList();
|
||||
|
||||
_parser.parse(entry.getEntry().getText(), this);
|
||||
|
||||
out.write("<!-- body begin -->\n");
|
||||
out.write("<!-- body meta begin -->\n");
|
||||
out.write("<tr class=\"postMeta\" id=\"" + post.toString() + "\">\n");
|
||||
|
||||
String subject = (String)_headers.get(HTMLRenderer.HEADER_SUBJECT);
|
||||
if (subject == null)
|
||||
subject = "";
|
||||
out.write(" <td colspan=\"3\" class=\"postMetaSubject\" id=\"bodySubject\">");
|
||||
out.write(subject);
|
||||
out.write("</td></tr>\n");
|
||||
out.write("<tr class=\"postMeta\"><td colspan=\"3\" class=\"postMetaLink\">\n");
|
||||
out.write("<a href=\"");
|
||||
out.write(getMetadataURL(post.getKeyHash()));
|
||||
out.write("\" title=\"View the author's profile\">");
|
||||
|
||||
String author = null;
|
||||
PetName pn = user.getPetNameDB().getByLocation(post.getKeyHash().toBase64());
|
||||
if (pn == null) {
|
||||
BlogInfo info = archive.getBlogInfo(post.getKeyHash());
|
||||
if (info != null)
|
||||
author = info.getProperty(BlogInfo.NAME);
|
||||
} else {
|
||||
author = pn.getName();
|
||||
}
|
||||
if ( (author == null) || (author.trim().length() <= 0) )
|
||||
author = post.getKeyHash().toBase64().substring(0,6);
|
||||
|
||||
ThreadNode node = index.getNode(post);
|
||||
|
||||
out.write(author);
|
||||
out.write("</a> @ ");
|
||||
out.write(getEntryDate(post.getEntryId()));
|
||||
|
||||
Collection tags = node.getTags();
|
||||
if ( (tags != null) && (tags.size() > 0) ) {
|
||||
out.write("\nTags: \n");
|
||||
for (Iterator tagIter = tags.iterator(); tagIter.hasNext(); ) {
|
||||
String tag = (String)tagIter.next();
|
||||
out.write("<a href=\"");
|
||||
out.write(getFilterByTagLink(baseURI, node, user, tag, filteredAuthor));
|
||||
out.write("\" title=\"Filter threads to only include posts tagged as '");
|
||||
out.write(tag);
|
||||
out.write("'\">");
|
||||
out.write(" " + tag);
|
||||
out.write("</a>\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.write("\n<a href=\"");
|
||||
out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags, filteredAuthor));
|
||||
out.write("\" title=\"Select a shareable link directly to this post\">permalink</a>\n");
|
||||
|
||||
|
||||
if (!inlineReply) {
|
||||
String refuseReply = (String)_headers.get(HEADER_REFUSE_REPLIES);
|
||||
boolean allowReply = false;
|
||||
if ( (refuseReply != null) && (Boolean.valueOf(refuseReply).booleanValue()) ) {
|
||||
if (_entry == null )
|
||||
allowReply = false;
|
||||
else if ( (_user == null) || (_user.getBlog() == null) )
|
||||
allowReply = false;
|
||||
else if (_entry.getURI().getKeyHash().equals(_user.getBlog()))
|
||||
allowReply = true;
|
||||
else
|
||||
allowReply = false;
|
||||
} else {
|
||||
allowReply = true;
|
||||
}
|
||||
if (allowReply && (_entry != null) ) {
|
||||
out.write("<a href=\"post.jsp?");
|
||||
out.write(PostServlet.PARAM_PARENT + '=' +
|
||||
Base64.encode(_entry.getURI().getKeyHash().toBase64() + '/' + _entry.getURI().getEntryId()));
|
||||
out.write("\" title=\"Reply to the current post\" >Reply</a><br />\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.write("</td>\n</tr>\n");
|
||||
out.write("<!-- body meta end -->\n");
|
||||
out.write("<!-- body post begin -->\n");
|
||||
out.write("<tr class=\"postData\">\n");
|
||||
out.write("<td colspan=\"3\">\n");
|
||||
out.write(_bodyBuffer.toString());
|
||||
out.write("</td>\n</tr>\n");
|
||||
out.write("<!-- body post end -->\n");
|
||||
out.write("<!-- body details begin -->\n");
|
||||
out.write(_postBodyBuffer.toString());
|
||||
/*
|
||||
"<tr class=\"postDetails\">\n" +
|
||||
" <form action=\"viewattachment.jsp\" method=\"GET\">\n" +
|
||||
" <td colspan=\"3\">\n" +
|
||||
" External links:\n" +
|
||||
" <a href=\"external.jsp?foo\" title=\"View foo.i2p\">http://foo.i2p/</a>\n" +
|
||||
" <a href=\"external.jsp?bar\" title=\"View bar.i2p\">http://bar.i2p/</a>\n" +
|
||||
" <br />\n" +
|
||||
" Attachments: <select name=\"attachment\">\n" +
|
||||
" <option value=\"0\">sampleRawSML.sml: Sample SML file with headers (4KB, type text/plain)</option>\n" +
|
||||
" </select> <input type=\"submit\" name=\"action\" value=\"Download\" />\n" +
|
||||
" <br /><a href=\"\" title=\"Expand the entire thread\">Full thread</a>\n" +
|
||||
" <a href=\"\" title=\"Previous post in the thread\">Prev in thread</a> \n" +
|
||||
" <a href=\"\" title=\"Next post in the thread\">Next in thread</a> \n" +
|
||||
" </td>\n" +
|
||||
" </form>\n" +
|
||||
"</tr>\n" +
|
||||
*/
|
||||
out.write("<!-- body details end -->\n");
|
||||
if (inlineReply && user.getAuthenticated() ) {
|
||||
String refuseReplies = (String)_headers.get(HTMLRenderer.HEADER_REFUSE_REPLIES);
|
||||
// show the reply form if we are the author or replies have not been explicitly rejected
|
||||
if ( (user.getBlog().equals(post.getKeyHash())) ||
|
||||
(refuseReplies == null) || (!Boolean.valueOf(refuseReplies).booleanValue()) ) {
|
||||
out.write("<!-- body reply begin -->\n");
|
||||
out.write("<form action=\"post.jsp\" method=\"POST\" enctype=\"multipart/form-data\">\n");
|
||||
out.write(replyHiddenFields);
|
||||
out.write("<input type=\"hidden\" name=\"" + PostServlet.PARAM_PARENT + "\" value=\"");
|
||||
out.write(Base64.encode(post.toString()));
|
||||
out.write("\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PostServlet.PARAM_SUBJECT + "\" value=\"");
|
||||
if (subject.indexOf("re: ") == -1)
|
||||
out.write("re: ");
|
||||
out.write(HTMLRenderer.sanitizeTagParam(subject));
|
||||
out.write("\" />");
|
||||
out.write("<tr class=\"postReply\">\n");
|
||||
out.write("<td colspan=\"3\">Reply: (<a href=\"smlref.jsp\" title=\"SML cheatsheet\" target=\"_blank\">SML reference</a>)</td>\n</tr>\n");
|
||||
out.write("<tr class=\"postReplyText\">\n");
|
||||
out.write("<td colspan=\"3\"><textarea name=\"" + PostServlet.PARAM_TEXT + "\" rows=\"2\" cols=\"100\"></textarea></td>\n");
|
||||
out.write("</tr>\n");
|
||||
out.write("<tr class=\"postReplyOptions\">\n");
|
||||
out.write(" <td colspan=\"3\">\n");
|
||||
out.write(" <input type=\"submit\" value=\"Preview...\" name=\"Post\" />\n");
|
||||
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PostServlet.PARAM_TAGS + "\" />\n");
|
||||
out.write(" in a new thread? <input type=\"checkbox\" name=\"" + PostServlet.PARAM_IN_NEW_THREAD + "\" value=\"true\" />\n");
|
||||
out.write(" refuse replies? <input type=\"checkbox\" name=\"" + PostServlet.PARAM_REFUSE_REPLIES + "\" value=\"true\" />\n");
|
||||
out.write(" attachment: <input type=\"file\" name=\"entryfile0\" />\n");
|
||||
out.write(" </td>\n</tr>\n</form>\n");
|
||||
out.write("<!-- body reply end -->\n");
|
||||
}
|
||||
}
|
||||
out.write("<!-- body end -->\n");
|
||||
}
|
||||
|
||||
public void receiveEnd() {
|
||||
_postBodyBuffer.append("<tr class=\"postDetails\">\n");
|
||||
_postBodyBuffer.append(" <form action=\"viewattachment.jsp\" method=\"GET\">\n");
|
||||
_postBodyBuffer.append(" <td colspan=\"3\" valign=\"top\" align=\"left\">\n");
|
||||
|
||||
_postBodyBuffer.append("<input type=\"hidden\" name=\"").append(ArchiveViewerBean.PARAM_BLOG);
|
||||
_postBodyBuffer.append("\" value=\"");
|
||||
if (_entry != null)
|
||||
_postBodyBuffer.append(Base64.encode(_entry.getURI().getKeyHash().getData()));
|
||||
else
|
||||
_postBodyBuffer.append("unknown");
|
||||
_postBodyBuffer.append("\" />\n");
|
||||
_postBodyBuffer.append("<input type=\"hidden\" name=\"").append(ArchiveViewerBean.PARAM_ENTRY);
|
||||
_postBodyBuffer.append("\" value=\"");
|
||||
if (_entry != null)
|
||||
_postBodyBuffer.append(_entry.getURI().getEntryId());
|
||||
else
|
||||
_postBodyBuffer.append("unknown");
|
||||
_postBodyBuffer.append("\" />\n");
|
||||
|
||||
//_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" ").append(getClass("summDetail")).append(" >\n");
|
||||
|
||||
if ( (_entry != null) && (_entry.getAttachments() != null) && (_entry.getAttachments().length > 0) ) {
|
||||
_postBodyBuffer.append(getSpan("summDetailAttachment")).append("Attachments:</span> ");
|
||||
_postBodyBuffer.append("<select ").append(getClass("summDetailAttachmentId")).append(" name=\"").append(ArchiveViewerBean.PARAM_ATTACHMENT).append("\">\n");
|
||||
for (int i = 0; i < _entry.getAttachments().length; i++) {
|
||||
_postBodyBuffer.append("<option value=\"").append(i).append("\">");
|
||||
Attachment a = _entry.getAttachments()[i];
|
||||
_postBodyBuffer.append(sanitizeString(a.getName()));
|
||||
if ( (a.getDescription() != null) && (a.getDescription().trim().length() > 0) ) {
|
||||
_postBodyBuffer.append(": ");
|
||||
_postBodyBuffer.append(sanitizeString(a.getDescription()));
|
||||
}
|
||||
_postBodyBuffer.append(" (").append(a.getDataLength()/1024).append("KB");
|
||||
_postBodyBuffer.append(", type ").append(sanitizeString(a.getMimeType())).append(")</option>\n");
|
||||
}
|
||||
_postBodyBuffer.append("</select>\n");
|
||||
_postBodyBuffer.append("<input ").append(getClass("summDetailAttachmentDl")).append(" type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
}
|
||||
|
||||
if (_blogs.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailBlog")).append("Blog references:</span>");
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
Blog b = (Blog)_blogs.get(i);
|
||||
_postBodyBuffer.append("<a ").append(getClass("summDetailBlogLink")).append(" href=\"");
|
||||
boolean expanded = (_user != null ? _user.getShowExpanded() : false);
|
||||
boolean images = (_user != null ? _user.getShowImages() : false);
|
||||
_postBodyBuffer.append(getPageURL(new Hash(Base64.decode(b.hash)), b.tag, b.entryId, -1, -1, expanded, images));
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(b.name)).append("</a> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_links.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailExternal")).append("External links:</span> ");
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
Link l = (Link)_links.get(i);
|
||||
_postBodyBuffer.append("<a ").append(getClass("summDetailExternalLink")).append(" href=\"externallink.jsp?");
|
||||
if (l.schema != null)
|
||||
_postBodyBuffer.append("schema=").append(sanitizeURL(l.schema)).append('&');
|
||||
if (l.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeURL(l.location)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(l.location, 60));
|
||||
_postBodyBuffer.append(getSpan("summDetailExternalNet")).append(" (").append(sanitizeString(l.schema)).append(")</span></a> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_addresses.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailAddr")).append("Addresses:</span>");
|
||||
for (int i = 0; i < _addresses.size(); i++) {
|
||||
Address a = (Address)_addresses.get(i);
|
||||
importAddress(a);
|
||||
PetName pn = null;
|
||||
if (_user != null)
|
||||
pn = _user.getPetNameDB().getByLocation(a.location);
|
||||
if (pn != null) {
|
||||
_postBodyBuffer.append(' ').append(getSpan("summDetailAddrKnown"));
|
||||
_postBodyBuffer.append(sanitizeString(pn.getName())).append("</span>");
|
||||
} else {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailAddrLink")).append(" href=\"addresses.jsp?");
|
||||
if (a.schema != null)
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NET).append("=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
if (a.location != null)
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_LOC).append("=").append(sanitizeTagParam(a.location)).append('&');
|
||||
if (a.name != null)
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_NAME).append("=").append(sanitizeTagParam(a.name)).append('&');
|
||||
if (a.protocol != null)
|
||||
_postBodyBuffer.append(AddressesServlet.PARAM_PROTO).append("=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_archives.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailArchive")).append("Archives:</span>");
|
||||
for (int i = 0; i < _archives.size(); i++) {
|
||||
ArchiveRef a = (ArchiveRef)_archives.get(i);
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveLink")).append(" href=\"").append(getArchiveURL(null, new SafeURL(a.locationSchema + "://" + a.location)));
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
if (a.description != null)
|
||||
_postBodyBuffer.append(": ").append(getSpan("summDetailArchiveDesc")).append(sanitizeString(a.description)).append("</span>");
|
||||
if (null == _user.getPetNameDB().getByLocation(a.location)) {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveBookmark")).append(" href=\"");
|
||||
_postBodyBuffer.append(getBookmarkURL(sanitizeTagParam(a.name), sanitizeTagParam(a.location), sanitizeTagParam(a.locationSchema), AddressesServlet.PROTO_ARCHIVE));
|
||||
_postBodyBuffer.append("\">bookmark it</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_entry != null) {
|
||||
List replies = _archive.getIndex().getReplies(_entry.getURI());
|
||||
if ( (replies != null) && (replies.size() > 0) ) {
|
||||
_postBodyBuffer.append(getSpan("summDetailReplies")).append("Replies:</span> ");
|
||||
for (int i = 0; i < replies.size(); i++) {
|
||||
BlogURI reply = (BlogURI)replies.get(i);
|
||||
_postBodyBuffer.append("<a ").append(getClass("summDetailReplyLink")).append(" href=\"");
|
||||
_postBodyBuffer.append(getPageURL(reply.getKeyHash(), null, reply.getEntryId(), -1, -1, true, _user.getShowImages()));
|
||||
_postBodyBuffer.append("\">");
|
||||
_postBodyBuffer.append(getSpan("summDetailReplyAuthor"));
|
||||
BlogInfo replyAuthor = _archive.getBlogInfo(reply);
|
||||
if (replyAuthor != null) {
|
||||
_postBodyBuffer.append(sanitizeString(replyAuthor.getProperty(BlogInfo.NAME)));
|
||||
} else {
|
||||
_postBodyBuffer.append(reply.getKeyHash().toBase64().substring(0,16));
|
||||
}
|
||||
_postBodyBuffer.append("</span> on ");
|
||||
_postBodyBuffer.append(getSpan("summDetailReplyDate"));
|
||||
_postBodyBuffer.append(getEntryDate(reply.getEntryId()));
|
||||
_postBodyBuffer.append("</a></span> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />");
|
||||
}
|
||||
}
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) ) {
|
||||
BlogURI replyURI = new BlogURI(inReplyTo);
|
||||
if (replyURI.getEntryId() > 0)
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailParent")).append(" href=\"").append(getPageURL(replyURI.getKeyHash(), null, replyURI.getEntryId(), 0, 0, true, true)).append("\">(view parent)</a><br />\n");
|
||||
}
|
||||
|
||||
_postBodyBuffer.append(" </td>\n");
|
||||
_postBodyBuffer.append(" </form>\n");
|
||||
_postBodyBuffer.append("</tr>\n");
|
||||
}
|
||||
|
||||
public void receiveHeaderEnd() {
|
||||
//_preBodyBuffer.append("<table ").append(getClass("overall")).append(" width=\"100%\" border=\"0\">\n");
|
||||
//renderSubjectCell();
|
||||
//renderMetaCell();
|
||||
//renderPreBodyCell();
|
||||
}
|
||||
|
||||
public String getMetadataURL(Hash blog) {
|
||||
return buildProfileURL(blog);
|
||||
}
|
||||
public static String buildProfileURL(Hash blog) {
|
||||
if ( (blog != null) && (blog.getData() != null) )
|
||||
return "profile.jsp?" + ThreadedHTMLRenderer.PARAM_AUTHOR + "=" +
|
||||
Base64.encode(blog.getData());
|
||||
else
|
||||
return "profile.jsp";
|
||||
}
|
||||
protected String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : false); }
|
||||
protected String getEntryURL(boolean showImages) {
|
||||
if (_entry == null)
|
||||
return _baseURI;
|
||||
else
|
||||
return _baseURI + '?' + PARAM_VIEW_POST + '=' +
|
||||
Base64.encode(_entry.getURI().getKeyHash().getData()) + '/'
|
||||
+ _entry.getURI().getEntryId() + '&';
|
||||
}
|
||||
|
||||
public String getPageURL(User user, String selector, int numPerPage, int pageNum) { return _baseURI; }
|
||||
|
||||
public String getPageURL(Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append(_baseURI).append('?');
|
||||
if ( (blog != null) && (entryId > 0) ) {
|
||||
buf.append(PARAM_VIEW_POST).append('=').append(Base64.encode(blog.getData())).append('/').append(entryId).append('&');
|
||||
buf.append(PARAM_VISIBLE).append('=').append(Base64.encode(blog.getData())).append('/').append(entryId).append('&');
|
||||
}
|
||||
if (tag != null)
|
||||
buf.append(PARAM_TAGS).append('=').append(sanitizeTagParam(tag)).append('&');
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
395
apps/syndie/java/src/net/i2p/syndie/web/AddressesServlet.java
Normal file
@@ -0,0 +1,395 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Show the user's addressbook
|
||||
*
|
||||
*/
|
||||
public class AddressesServlet extends BaseServlet {
|
||||
public static final String PARAM_IS_PUBLIC = "addrPublic";
|
||||
public static final String PARAM_NAME = "addrName";
|
||||
public static final String PARAM_LOC = "addrLoc";
|
||||
public static final String PARAM_FAVORITE = "addrFavorite";
|
||||
public static final String PARAM_IGNORE = "addrIgnore";
|
||||
public static final String PARAM_NET = "addrNet";
|
||||
public static final String PARAM_PROTO = "addrProto";
|
||||
public static final String PARAM_SYNDICATE = "addrSyndicate";
|
||||
public static final String PARAM_ACTION = "action";
|
||||
|
||||
public static final String PROTO_BLOG = "syndieblog";
|
||||
public static final String PROTO_ARCHIVE = "syndiearchive";
|
||||
public static final String PROTO_I2PHEX = "i2phex";
|
||||
public static final String PROTO_EEPSITE = "eep";
|
||||
|
||||
public static final String NET_SYNDIE = "syndie";
|
||||
public static final String NET_I2P = "i2p";
|
||||
public static final String NET_IP = "ip";
|
||||
public static final String NET_FREENET = "freenet";
|
||||
public static final String NET_TOR = "tor";
|
||||
|
||||
public static final String ACTION_DELETE_BLOG = "Delete author";
|
||||
public static final String ACTION_UPDATE_BLOG = "Update author";
|
||||
public static final String ACTION_ADD_BLOG = "Add author";
|
||||
|
||||
public static final String ACTION_DELETE_ARCHIVE = "Delete archive";
|
||||
public static final String ACTION_UPDATE_ARCHIVE = "Update archive";
|
||||
public static final String ACTION_ADD_ARCHIVE = "Add archive";
|
||||
|
||||
public static final String ACTION_DELETE_PEER = "Delete peer";
|
||||
public static final String ACTION_UPDATE_PEER = "Update peer";
|
||||
public static final String ACTION_ADD_PEER = "Add peer";
|
||||
|
||||
public static final String ACTION_DELETE_EEPSITE = "Delete eepsite";
|
||||
public static final String ACTION_UPDATE_EEPSITE = "Update eepsite";
|
||||
public static final String ACTION_ADD_EEPSITE = "Add eepsite";
|
||||
|
||||
public static final String ACTION_DELETE_OTHER = "Delete address";
|
||||
public static final String ACTION_UPDATE_OTHER = "Update address";
|
||||
public static final String ACTION_ADD_OTHER = "Add other address";
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
if (!user.getAuthenticated()) {
|
||||
out.write("<tr><td colspan=\"3\">You must log in to view your addressbook</d></tr>\n");
|
||||
} else {
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
String uri = req.getRequestURI();
|
||||
|
||||
PetName pn = buildNewName(req, PROTO_BLOG);
|
||||
_log.debug("pn for protoBlog [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
|
||||
renderBlogs(user, db, uri, pn, out);
|
||||
pn = buildNewName(req, PROTO_ARCHIVE);
|
||||
_log.debug("pn for protoArchive [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
|
||||
renderArchives(user, db, uri, pn, out);
|
||||
pn = buildNewName(req, PROTO_I2PHEX);
|
||||
_log.debug("pn for protoPhex [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
|
||||
renderI2Phex(user, db, uri, pn, out);
|
||||
pn = buildNewName(req, PROTO_EEPSITE);
|
||||
_log.debug("pn for protoEep [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
|
||||
renderEepsites(user, db, uri, pn, out);
|
||||
pn = buildNewName(req);
|
||||
_log.debug("pn for proto other [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
|
||||
renderOther(user, db, uri, pn, out);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderBlogs(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if (PROTO_BLOG.equals(pn.getProtocol()))
|
||||
names.add(name);
|
||||
}
|
||||
out.write("<tr><td colspan=\"3\"><b>Syndie authors</b></td></tr>\n");
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_BLOG + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName() + "\" />" + pn.getName() + " ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + pn.getLocation() + "\" /> ");
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE))
|
||||
out.write("Favorite? <input type=\"checkbox\" name=\"" + PARAM_FAVORITE + "\" checked=\"true\" value=\"true\" /> ");
|
||||
else
|
||||
out.write("Favorite? <input type=\"checkbox\" name=\"" + PARAM_FAVORITE + "\" value=\"true\" /> ");
|
||||
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) {
|
||||
out.write("Ignored? <input type=\"checkbox\" name=\"" + PARAM_IGNORE + "\" checked=\"true\" value=\"true\" /> ");
|
||||
} else {
|
||||
out.write("Ignored? <input type=\"checkbox\" name=\"" + PARAM_IGNORE + "\" value=\"true\" /> ");
|
||||
out.write("<a href=\"" + getControlTarget() + "?" + ThreadedHTMLRenderer.PARAM_AUTHOR + '='
|
||||
+ pn.getLocation() + "\" title=\"View threads by the given author\">View posts</a> ");
|
||||
}
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_BLOG + "\" /> ");
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_UPDATE_BLOG + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_BLOG + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName() + "\" /> ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + newName.getLocation() + "\" /> ");
|
||||
if (newName.isMember(FilteredThreadIndex.GROUP_FAVORITE))
|
||||
out.write("Favorite? <input type=\"checkbox\" name=\"" + PARAM_FAVORITE + "\" checked=\"true\" value=\"true\" /> ");
|
||||
else
|
||||
out.write("Favorite? <input type=\"checkbox\" name=\"" + PARAM_FAVORITE + "\" value=\"true\" /> ");
|
||||
|
||||
if (newName.isMember(FilteredThreadIndex.GROUP_IGNORE)) {
|
||||
out.write("Ignored? <input type=\"checkbox\" name=\"" + PARAM_IGNORE + "\" checked=\"true\" value=\"true\" /> ");
|
||||
} else {
|
||||
out.write("Ignored? <input type=\"checkbox\" name=\"" + PARAM_IGNORE + "\" value=\"true\" /> ");
|
||||
}
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_BLOG + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
}
|
||||
|
||||
private void renderArchives(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if (PROTO_ARCHIVE.equals(pn.getProtocol()))
|
||||
names.add(name);
|
||||
}
|
||||
out.write("<tr><td colspan=\"3\"><b>Syndie archives</b></td></tr>\n");
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_ARCHIVE + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + pn.getName() + "\" />" + pn.getName() + " ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"20\" value=\"" + pn.getLocation() + "\" /> ");
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
|
||||
if (BlogManager.instance().syndicationScheduled(pn.getLocation()))
|
||||
out.write("Syndicate? <input type=\"checkbox\" name=\"" + PARAM_SYNDICATE + "\" checked=\"true\" value=\"true\" />");
|
||||
else
|
||||
out.write("Syndicate? <input type=\"checkbox\" name=\"" + PARAM_SYNDICATE + "\" value=\"true\" />");
|
||||
|
||||
out.write("<a href=\"" + getSyndicateLink(user, pn.getLocation())
|
||||
+ "\" title=\"Synchronize manually with the peer\">Sync manually</a> ");
|
||||
}
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_ARCHIVE + "\" /> ");
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_UPDATE_ARCHIVE + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_ARCHIVE + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName() + "\" /> ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"20\" value=\"" + newName.getLocation() + "\" /> ");
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
if (BlogManager.instance().syndicationScheduled(newName.getLocation()))
|
||||
out.write("Syndicate? <input type=\"checkbox\" name=\"" + PARAM_SYNDICATE + "\" checked=\"true\" value=\"true\" />");
|
||||
else
|
||||
out.write("Syndicate? <input type=\"checkbox\" name=\"" + PARAM_SYNDICATE + "\" value=\"true\" />");
|
||||
}
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_ARCHIVE + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
}
|
||||
|
||||
private void renderI2Phex(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if (PROTO_I2PHEX.equals(pn.getProtocol()))
|
||||
names.add(name);
|
||||
}
|
||||
out.write("<tr><td colspan=\"3\"><b>I2Phex peers</b></td></tr>\n");
|
||||
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_I2PHEX + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName() + "\" />" + pn.getName() + " ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + pn.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_PEER + "\" /> ");
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_UPDATE_PEER + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_I2PHEX + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName() + "\" /> ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + newName.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_PEER + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
}
|
||||
private void renderEepsites(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if (PROTO_EEPSITE.equals(pn.getProtocol()))
|
||||
names.add(name);
|
||||
}
|
||||
out.write("<tr><td colspan=\"3\"><b>Eepsites</b></td></tr>\n");
|
||||
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_EEPSITE + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName() + "\" />" + pn.getName() + " ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + pn.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_EEPSITE + "\" /> ");
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_UPDATE_EEPSITE + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_EEPSITE + "\" />");
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName() + "\" /> ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + newName.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_EEPSITE + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
}
|
||||
private void renderOther(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if (isRightProtocol(pn.getProtocol()))
|
||||
names.add(name);
|
||||
}
|
||||
out.write("<tr><td colspan=\"3\"><b>Other addresses</b></td></tr>\n");
|
||||
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Network: <input type=\"text\" name=\"" + PARAM_NET + "\" value=\"" + pn.getNetwork() + "\" /> ");
|
||||
out.write("Protocol: <input type=\"text\" name=\"" + PARAM_PROTO + "\" value=\"" + pn.getProtocol() + "\" /> ");
|
||||
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName() + "\" />" + pn.getName() +" ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + pn.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_OTHER + "\" /> ");
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_UPDATE_OTHER + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
|
||||
out.write("Network: <input type=\"text\" name=\"" + PARAM_NET + "\" value=\"" + newName.getNetwork() + "\" /> ");
|
||||
out.write("Protocol: <input type=\"text\" name=\"" + PARAM_PROTO + "\" value=\"" + newName.getProtocol() + "\" /> ");
|
||||
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName() + "\" /> ");
|
||||
out.write("Location: <input type=\"text\" name=\"" + PARAM_LOC + "\" size=\"3\" value=\"" + newName.getLocation() + "\" /> ");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_OTHER + "\" /> ");
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
}
|
||||
|
||||
/** build the 'other' name passed in */
|
||||
private PetName buildNewName(HttpServletRequest req) { return buildNewName(req, null); }
|
||||
/** build a petname based by the request passed in, if the new entry is of the given protocol */
|
||||
private PetName buildNewName(HttpServletRequest req, String protocol) {
|
||||
PetName pn = new PetName();
|
||||
if (!isRightProtocol(req, protocol)) {
|
||||
pn.setIsPublic(true);
|
||||
pn.setName("");
|
||||
pn.setLocation("");
|
||||
if (protocol == null)
|
||||
pn.setProtocol("");
|
||||
else
|
||||
pn.setProtocol(protocol);
|
||||
pn.setNetwork("");
|
||||
return pn;
|
||||
} else {
|
||||
pn = buildNewAddress(req);
|
||||
}
|
||||
return pn;
|
||||
}
|
||||
|
||||
private String getParam(HttpServletRequest req, String param) {
|
||||
if (empty(req, param)) {
|
||||
return "";
|
||||
} else {
|
||||
String val = req.getParameter(param);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isRightProtocol(HttpServletRequest req, String protocol) {
|
||||
// if they hit submit, they are actually updating stuff, so don't include a 'new' one
|
||||
if (!empty(req, PARAM_ACTION))
|
||||
return false;
|
||||
|
||||
return isRightProtocol(protocol, req.getParameter(PARAM_PROTO));
|
||||
}
|
||||
private boolean isRightProtocol(String proto) { return isRightProtocol((String)null, proto); }
|
||||
private boolean isRightProtocol(String proto, String reqProto) {
|
||||
if (empty(reqProto))
|
||||
return false;
|
||||
if (proto == null) {
|
||||
if (PROTO_ARCHIVE.equals(reqProto) ||
|
||||
PROTO_BLOG.equals(reqProto) ||
|
||||
PROTO_EEPSITE.equals(reqProto) ||
|
||||
PROTO_I2PHEX.equals(reqProto))
|
||||
return false;
|
||||
else // its something other than the four default types
|
||||
return true;
|
||||
} else {
|
||||
return proto.equals(reqProto);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTitle() { return "Syndie :: Addressbook"; }
|
||||
}
|
||||
77
apps/syndie/java/src/net/i2p/syndie/web/AdminServlet.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Admin form
|
||||
*
|
||||
*/
|
||||
public class AdminServlet extends BaseServlet {
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
displayForm(user, req, out);
|
||||
} else {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_adminMsgErr\">You are not authorized to configure this Syndie instance</span></td></tr>\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void displayForm(User user, HttpServletRequest req, PrintWriter out) throws IOException {
|
||||
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">\n");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
|
||||
out.write("<em class=\"b_adminField\">Single user?</em> <input type=\"checkbox\" class=\"b_adminField\" name=\"singleuser\" ");
|
||||
if (BlogManager.instance().isSingleUser())
|
||||
out.write(" checked=\"true\" ");
|
||||
out.write(" /><br />\n");
|
||||
|
||||
out.write("<span class=\"b_adminDescr\">If this is checked, the registration, admin, and remote passwords are unnecessary - anyone");
|
||||
out.write("can register and administer Syndie, as well as use any remote functionality. This should not be checked if untrusted");
|
||||
out.write("parties can access this web interface.</span><br />\n");
|
||||
out.write("<span class=\"b_adminField\">Default user:</span> <input class=\"b_adminField\" type=\"text\" name=\"defaultUser\" size=\"10\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultLogin());
|
||||
out.write("\" />\n");
|
||||
out.write("<span class=\"b_adminField\">pass:</span> <input class=\"b_adminField\" type=\"text\" name=\"defaultPass\" size=\"10\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultPass());
|
||||
out.write("\"/><br />\n");
|
||||
out.write("<span class=\"b_adminDescr\">If Syndie is in single user mode, it will create a new 'default' user automatically and use that ");
|
||||
out.write("whenever you access Syndie unless you explicitly log in to another account. If you want Syndie to use an existing account as ");
|
||||
out.write("your default account, you can specify them here, in which case it will automatically log you in under that account.</span><br />\n");
|
||||
out.write("<em class=\"b_adminField\">Registration password:</em> <input class=\"b_adminField\" type=\"text\" name=\"regpass\" size=\"10\" value=\"\" /><br />\n");
|
||||
out.write("<span class=\"b_adminDescr\">Users must specify this password on the registration form to proceed. If this is ");
|
||||
out.write("blank, anyone can register.</span><br />\n");
|
||||
out.write("<em class=\"b_adminField\">Remote password:</em> <input class=\"b_adminField\" type=\"text\" name=\"remotepass\" size=\"10\" value=\"\" /><br />\n");
|
||||
out.write("<span class=\"b_adminDescr\">To access remote archives, users must first provide this password on their ");
|
||||
out.write("metadata page. Remote access is 'dangerous', as it allows the user to instruct ");
|
||||
out.write("this Syndie instance to establish HTTP connections with arbitrary locations. If ");
|
||||
out.write("this field is not specified, no one can use remote archives.</span><br />\n");
|
||||
out.write("<em class=\"b_adminField\">Default remote proxy host:</em> <input class=\"b_adminField\" type=\"text\" name=\"proxyhost\" size=\"20\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultProxyHost());
|
||||
out.write("\" /><br />\n");
|
||||
out.write("<em class=\"b_adminField\">Default remote proxy port:</em> <input class=\"b_adminField\" type=\"text\" name=\"proxyport\" size=\"5\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultProxyPort());
|
||||
out.write("\" /><br />\n");
|
||||
out.write("<span class=\"b_adminDescr\">This is the default HTTP proxy shown on the remote archive page.</span><br />\n");
|
||||
out.write("<hr />\n");
|
||||
out.write("<input class=\"b_adminSave\" type=\"submit\" name=\"action\" value=\"Save config\" />\n");
|
||||
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
protected String getTitle() { return "Syndie :: Configuration"; }
|
||||
}
|
||||
@@ -19,6 +19,20 @@ import net.i2p.syndie.data.*;
|
||||
public class ArchiveServlet extends HttpServlet {
|
||||
|
||||
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handle(req, resp);
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handle(req, resp);
|
||||
}
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handle(req, resp);
|
||||
}
|
||||
public void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
handle(req, resp);
|
||||
}
|
||||
|
||||
public void handle(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String path = req.getPathInfo();
|
||||
if ( (path == null) || (path.trim().length() <= 1) ) {
|
||||
renderRootIndex(resp);
|
||||
|
||||
@@ -405,15 +405,13 @@ public class ArchiveViewerBean {
|
||||
start = 0;
|
||||
end = entries.size() - 1;
|
||||
} else {
|
||||
HTMLRenderer rend = new ThreadedHTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
pages = entries.size() / numPerPage;
|
||||
if (numPerPage * pages < entries.size())
|
||||
pages++;
|
||||
if (pageNum > 0) {
|
||||
String prevURL = null;
|
||||
if ( (selector == null) || (selector.trim().length() <= 0) )
|
||||
prevURL = HTMLRenderer.getPageURL(blog, tag, entryId, group, numPerPage, pageNum-1, expandEntries, showImages);
|
||||
else
|
||||
prevURL = HTMLRenderer.getPageURL(user, selector, numPerPage, pageNum-1);
|
||||
prevURL = rend.getPageURL(blog, tag, entryId, group, numPerPage, pageNum-1, expandEntries, showImages);
|
||||
//System.out.println("prevURL: " + prevURL);
|
||||
out.write(" <a class=\"b_selectorPrevMore\" href=\"" + prevURL + "\"><<</a>");
|
||||
} else {
|
||||
@@ -422,10 +420,7 @@ public class ArchiveViewerBean {
|
||||
out.write("<span class=\"b_selectorPage\">Page " + (pageNum+1) + " of " + pages + "</span>");
|
||||
if (pageNum + 1 < pages) {
|
||||
String nextURL = null;
|
||||
if ( (selector == null) || (selector.trim().length() <= 0) )
|
||||
nextURL = HTMLRenderer.getPageURL(blog, tag, entryId, group, numPerPage, pageNum+1, expandEntries, showImages);
|
||||
else
|
||||
nextURL = HTMLRenderer.getPageURL(user, selector, numPerPage, pageNum+1);
|
||||
nextURL = rend.getPageURL(blog, tag, entryId, group, numPerPage, pageNum+1, expandEntries, showImages);
|
||||
//System.out.println("nextURL: " + nextURL);
|
||||
out.write(" <a class=\"b_selectorNextMore\" href=\"" + nextURL + "\">>></a>");
|
||||
} else {
|
||||
@@ -749,8 +744,7 @@ public class ArchiveViewerBean {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (props[i].equals(BlogInfo.OWNER_KEY)) {
|
||||
out.write("<tr class=\"b_metaBlog\"><td class=\"b_metaBlog\"><span class=\"b_metaBlog\">Blog:</span></td>");
|
||||
String blogURL = HTMLRenderer.getPageURL(blog, null, -1, -1, -1, false, false);
|
||||
out.write("<td class=\"b_metaBlog\"><a class=\"b_metaBlog\" href=\"" + blogURL + "\">" + Base64.encode(blog.getData()) + "</td></tr>\n");
|
||||
out.write("<td class=\"b_metaBlog\">" + Base64.encode(blog.getData()) + "</td></tr>\n");
|
||||
} else if (props[i].equals(BlogInfo.SIGNATURE)) {
|
||||
continue;
|
||||
} else if (props[i].equals(BlogInfo.POSTERS)) {
|
||||
@@ -782,7 +776,8 @@ public class ArchiveViewerBean {
|
||||
out.write("<tr class=\"b_metaTags\"><td class=\"b_metaTags\"><span class=\"b_metaTags\">Known tags:</span></td><td class=\"b_metaTags\">");
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
String tag = (String)tags.get(i);
|
||||
out.write("<a class=\"b_metaTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, false, false) + "\">" +
|
||||
HTMLRenderer rend = new HTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
out.write("<a class=\"b_metaTag\" href=\"" + rend.getPageURL(blog, tag, -1, -1, -1, false, false) + "\">" +
|
||||
HTMLRenderer.sanitizeString(tag) + "</a> ");
|
||||
}
|
||||
out.write("</td></tr>");
|
||||
|
||||
988
apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java
Normal file
@@ -0,0 +1,988 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Base servlet for handling request and rendering the templates
|
||||
*
|
||||
*/
|
||||
public abstract class BaseServlet extends HttpServlet {
|
||||
protected static final String PARAM_AUTH_ACTION = "syndie.auth";
|
||||
private static long _authNonce;
|
||||
private I2PAppContext _context;
|
||||
protected Log _log;
|
||||
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(getClass());
|
||||
_authNonce = _context.random().nextLong();
|
||||
}
|
||||
|
||||
protected boolean authAction(HttpServletRequest req) {
|
||||
return authAction(req.getParameter(PARAM_AUTH_ACTION));
|
||||
}
|
||||
protected boolean authAction(String auth) {
|
||||
if (auth == null) {
|
||||
return false;
|
||||
} else {
|
||||
try {
|
||||
boolean rv = (Long.valueOf(auth).longValue() == _authNonce);
|
||||
return rv;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write out hidden fields for params that need to be tacked onto an http request that updates
|
||||
* data, to prevent spoofing
|
||||
*/
|
||||
protected void writeAuthActionFields(Writer out) throws IOException {
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_AUTH_ACTION + "\" value=\"" + _authNonce + "\" />");
|
||||
}
|
||||
protected String getAuthActionFields() throws IOException {
|
||||
return "<input type=\"hidden\" name=\"" + PARAM_AUTH_ACTION + "\" value=\"" + _authNonce + "\" />";
|
||||
}
|
||||
/**
|
||||
* key=value& of params that need to be tacked onto an http request that updates data, to
|
||||
* prevent spoofing
|
||||
*/
|
||||
protected String getAuthActionParams() { return PARAM_AUTH_ACTION + '=' + _authNonce + '&'; }
|
||||
/**
|
||||
* key=value& of params that need to be tacked onto an http request that updates data, to
|
||||
* prevent spoofing
|
||||
*/
|
||||
protected void addAuthActionParams(StringBuffer buf) {
|
||||
buf.append(PARAM_AUTH_ACTION).append('=').append(_authNonce).append('&');
|
||||
}
|
||||
|
||||
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
req.setCharacterEncoding("UTF-8");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("text/html");
|
||||
|
||||
User user = (User)req.getSession().getAttribute("user");
|
||||
String login = req.getParameter("login");
|
||||
String pass = req.getParameter("password");
|
||||
String action = req.getParameter("action");
|
||||
boolean forceNewIndex = false;
|
||||
|
||||
boolean authAction = authAction(req);
|
||||
|
||||
if (req.getParameter("regenerateIndex") != null)
|
||||
forceNewIndex = true;
|
||||
|
||||
User oldUser = user;
|
||||
if (authAction)
|
||||
user = handleRegister(user, req);
|
||||
if (oldUser != user)
|
||||
forceNewIndex = true;
|
||||
|
||||
if (user == null) {
|
||||
if ("Login".equals(action)) {
|
||||
user = BlogManager.instance().login(login, pass); // ignore failures - user will just be unauthorized
|
||||
if (!user.getAuthenticated()) {
|
||||
user = BlogManager.instance().getDefaultUser();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explicit login failed for [" + login + "], using default login");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explicit login successful for [" + login + "]");
|
||||
}
|
||||
} else {
|
||||
user = BlogManager.instance().getDefaultUser();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Implicit login for the default user");
|
||||
}
|
||||
forceNewIndex = true;
|
||||
} else if (authAction && "Login".equals(action)) {
|
||||
user = BlogManager.instance().login(login, pass); // ignore failures - user will just be unauthorized
|
||||
if (!user.getAuthenticated()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explicit relogin failed for [" + login + "] from [" + user.getUsername() + "], using default user");
|
||||
user = BlogManager.instance().getDefaultUser();
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explicit relogin successful for [" + login + "] from [" + user.getUsername() + "]");
|
||||
}
|
||||
forceNewIndex = true;
|
||||
} else if (authAction && "Logout".equals(action)) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explicit logout successful for [" + user.getUsername() + "], using default login");
|
||||
user = BlogManager.instance().getDefaultUser();
|
||||
forceNewIndex = true;
|
||||
}
|
||||
|
||||
req.getSession().setAttribute("user", user);
|
||||
|
||||
if (authAction) {
|
||||
handleAdmin(user, req);
|
||||
|
||||
forceNewIndex = handleAddressbook(user, req) || forceNewIndex;
|
||||
forceNewIndex = handleBookmarking(user, req) || forceNewIndex;
|
||||
handleUpdateProfile(user, req);
|
||||
}
|
||||
|
||||
// the 'dataImported' flag is set by successful fetches in the SyndicateServlet/RemoteArchiveBean
|
||||
if (user.resetDataImported()) {
|
||||
forceNewIndex = true;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Data imported, force regenerate");
|
||||
}
|
||||
|
||||
FilteredThreadIndex index = (FilteredThreadIndex)req.getSession().getAttribute("threadIndex");
|
||||
|
||||
Collection tags = getFilteredTags(req);
|
||||
Collection filteredAuthors = getFilteredAuthors(req);
|
||||
boolean tagsChanged = ( (index != null) && (!index.getFilteredTags().equals(tags)) );
|
||||
boolean authorsChanged = ( (index != null) && (!index.getFilteredAuthors().equals(filteredAuthors)) );
|
||||
if (forceNewIndex || (index == null) || (tagsChanged) || (authorsChanged) ) {
|
||||
index = new FilteredThreadIndex(user, BlogManager.instance().getArchive(), getFilteredTags(req), filteredAuthors);
|
||||
req.getSession().setAttribute("threadIndex", index);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("New filtered index created (forced? " + forceNewIndex + ", tagsChanged? " + tagsChanged + ", authorsChanged? " + authorsChanged + ")");
|
||||
}
|
||||
|
||||
render(user, req, resp.getWriter(), index);
|
||||
}
|
||||
|
||||
private boolean handleBookmarking(User user, HttpServletRequest req) {
|
||||
if (!user.getAuthenticated())
|
||||
return false;
|
||||
|
||||
boolean rv = false;
|
||||
|
||||
String loc = req.getParameter(ThreadedHTMLRenderer.PARAM_ADD_TO_GROUP_LOCATION);
|
||||
String group = req.getParameter(ThreadedHTMLRenderer.PARAM_ADD_TO_GROUP_NAME);
|
||||
if ( (loc != null) && (group != null) && (group.trim().length() > 0) ) {
|
||||
try {
|
||||
Hash key = new Hash();
|
||||
key.fromBase64(loc);
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
PetName pn = db.getByLocation(loc);
|
||||
boolean isNew = false;
|
||||
if (pn == null) {
|
||||
isNew = true;
|
||||
BlogInfo info = BlogManager.instance().getArchive().getBlogInfo(key);
|
||||
String name = null;
|
||||
if (info != null)
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
else
|
||||
name = loc.substring(0,6);
|
||||
|
||||
if (db.containsName(name)) {
|
||||
int i = 0;
|
||||
while (db.containsName(name + i))
|
||||
i++;
|
||||
name = name + i;
|
||||
}
|
||||
|
||||
pn = new PetName(name, AddressesServlet.NET_SYNDIE, AddressesServlet.PROTO_BLOG, loc);
|
||||
}
|
||||
pn.addGroup(group);
|
||||
if (isNew)
|
||||
db.add(pn);
|
||||
BlogManager.instance().saveUser(user);
|
||||
// if we are ignoring someone, we need to recalculate the filters
|
||||
if (FilteredThreadIndex.GROUP_IGNORE.equals(group))
|
||||
rv = true;
|
||||
} catch (DataFormatException dfe) {
|
||||
// bad loc, ignore
|
||||
}
|
||||
}
|
||||
|
||||
String name = req.getParameter(ThreadedHTMLRenderer.PARAM_REMOVE_FROM_GROUP_NAME);
|
||||
group = req.getParameter(ThreadedHTMLRenderer.PARAM_REMOVE_FROM_GROUP);
|
||||
if ( (name != null) && (name.trim().length() > 0) ) {
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
PetName pn = db.getByName(name);
|
||||
boolean changed = false;
|
||||
if (pn != null) {
|
||||
if ( (group != null) && (group.trim().length() > 0) ) {
|
||||
// just remove them from the group
|
||||
changed = pn.isMember(group);
|
||||
pn.removeGroup(group);
|
||||
if ( (changed) && (FilteredThreadIndex.GROUP_IGNORE.equals(group)) )
|
||||
rv = true;
|
||||
} else {
|
||||
// remove it completely
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE))
|
||||
rv = true;
|
||||
db.remove(pn);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
BlogManager.instance().saveUser(user);
|
||||
}
|
||||
|
||||
if (rv)
|
||||
_log.debug("Bookmarking required rebuild");
|
||||
return rv;
|
||||
}
|
||||
|
||||
private boolean handleAddressbook(User user, HttpServletRequest req) {
|
||||
if ( (!user.getAuthenticated()) || (empty(AddressesServlet.PARAM_ACTION)) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String action = req.getParameter(AddressesServlet.PARAM_ACTION);
|
||||
|
||||
if ( (AddressesServlet.ACTION_ADD_ARCHIVE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_ADD_BLOG.equals(action)) ||
|
||||
(AddressesServlet.ACTION_ADD_EEPSITE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_ADD_OTHER.equals(action)) ||
|
||||
(AddressesServlet.ACTION_ADD_PEER.equals(action)) ) {
|
||||
PetName pn = buildNewAddress(req);
|
||||
if ( (pn != null) && (pn.getName() != null) && (pn.getLocation() != null) &&
|
||||
(!user.getPetNameDB().containsName(pn.getName())) ) {
|
||||
user.getPetNameDB().add(pn);
|
||||
BlogManager.instance().saveUser(user);
|
||||
|
||||
updateSyndication(user, pn.getLocation(), !empty(req, AddressesServlet.PARAM_SYNDICATE));
|
||||
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE) ||
|
||||
pn.isMember(FilteredThreadIndex.GROUP_IGNORE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else {
|
||||
// not valid, ignore
|
||||
return false;
|
||||
}
|
||||
} else if ( (AddressesServlet.ACTION_UPDATE_ARCHIVE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_UPDATE_BLOG.equals(action)) ||
|
||||
(AddressesServlet.ACTION_UPDATE_EEPSITE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_UPDATE_OTHER.equals(action)) ||
|
||||
(AddressesServlet.ACTION_UPDATE_PEER.equals(action)) ) {
|
||||
return updateAddress(user, req);
|
||||
} else if ( (AddressesServlet.ACTION_DELETE_ARCHIVE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_DELETE_BLOG.equals(action)) ||
|
||||
(AddressesServlet.ACTION_DELETE_EEPSITE.equals(action)) ||
|
||||
(AddressesServlet.ACTION_DELETE_OTHER.equals(action)) ||
|
||||
(AddressesServlet.ACTION_DELETE_PEER.equals(action)) ) {
|
||||
PetName pn = user.getPetNameDB().getByName(req.getParameter(AddressesServlet.PARAM_NAME));
|
||||
if (pn != null) {
|
||||
user.getPetNameDB().remove(pn);
|
||||
BlogManager.instance().saveUser(user);
|
||||
updateSyndication(user, pn.getLocation(), false);
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE) ||
|
||||
pn.isMember(FilteredThreadIndex.GROUP_IGNORE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// not an addressbook op
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateAddress(User user, HttpServletRequest req) {
|
||||
PetName pn = user.getPetNameDB().getByName(req.getParameter(AddressesServlet.PARAM_NAME));
|
||||
if (pn != null) {
|
||||
boolean wasIgnored = pn.isMember(FilteredThreadIndex.GROUP_IGNORE);
|
||||
boolean wasFavorite = pn.isMember(FilteredThreadIndex.GROUP_FAVORITE);
|
||||
|
||||
pn.setIsPublic(!empty(req, AddressesServlet.PARAM_IS_PUBLIC));
|
||||
pn.setLocation(req.getParameter(AddressesServlet.PARAM_LOC));
|
||||
pn.setNetwork(req.getParameter(AddressesServlet.PARAM_NET));
|
||||
pn.setProtocol(req.getParameter(AddressesServlet.PARAM_PROTO));
|
||||
if (empty(req, AddressesServlet.PARAM_FAVORITE))
|
||||
pn.removeGroup(FilteredThreadIndex.GROUP_FAVORITE);
|
||||
else
|
||||
pn.addGroup(FilteredThreadIndex.GROUP_FAVORITE);
|
||||
if (empty(req, AddressesServlet.PARAM_IGNORE))
|
||||
pn.removeGroup(FilteredThreadIndex.GROUP_IGNORE);
|
||||
else
|
||||
pn.addGroup(FilteredThreadIndex.GROUP_IGNORE);
|
||||
|
||||
BlogManager.instance().saveUser(user);
|
||||
|
||||
if (AddressesServlet.PROTO_ARCHIVE.equals(pn.getProtocol()))
|
||||
updateSyndication(user, pn.getLocation(), !empty(req, AddressesServlet.PARAM_SYNDICATE));
|
||||
|
||||
return (wasIgnored != pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) ||
|
||||
(wasFavorite != pn.isMember(FilteredThreadIndex.GROUP_IGNORE));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateSyndication(User user, String loc, boolean shouldAutomate) {
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
if (shouldAutomate)
|
||||
BlogManager.instance().scheduleSyndication(loc);
|
||||
else
|
||||
BlogManager.instance().unscheduleSyndication(loc);
|
||||
}
|
||||
}
|
||||
|
||||
protected PetName buildNewAddress(HttpServletRequest req) {
|
||||
PetName pn = new PetName();
|
||||
pn.setName(req.getParameter(AddressesServlet.PARAM_NAME));
|
||||
pn.setIsPublic(!empty(req, AddressesServlet.PARAM_IS_PUBLIC));
|
||||
pn.setLocation(req.getParameter(AddressesServlet.PARAM_LOC));
|
||||
pn.setNetwork(req.getParameter(AddressesServlet.PARAM_NET));
|
||||
pn.setProtocol(req.getParameter(AddressesServlet.PARAM_PROTO));
|
||||
if (empty(req, AddressesServlet.PARAM_FAVORITE))
|
||||
pn.removeGroup(FilteredThreadIndex.GROUP_FAVORITE);
|
||||
else
|
||||
pn.addGroup(FilteredThreadIndex.GROUP_FAVORITE);
|
||||
if (empty(req, AddressesServlet.PARAM_IGNORE))
|
||||
pn.removeGroup(FilteredThreadIndex.GROUP_IGNORE);
|
||||
else
|
||||
pn.addGroup(FilteredThreadIndex.GROUP_IGNORE);
|
||||
return pn;
|
||||
}
|
||||
|
||||
protected void handleUpdateProfile(User user, HttpServletRequest req) {
|
||||
if ( (user == null) || (!user.getAuthenticated()) || (user.getBlog() == null) )
|
||||
return;
|
||||
|
||||
String action = req.getParameter("action");
|
||||
if ( (action == null) || !("Update profile".equals(action)) )
|
||||
return;
|
||||
|
||||
String name = req.getParameter(ThreadedHTMLRenderer.PARAM_PROFILE_NAME);
|
||||
String desc = req.getParameter(ThreadedHTMLRenderer.PARAM_PROFILE_DESC);
|
||||
String url = req.getParameter(ThreadedHTMLRenderer.PARAM_PROFILE_URL);
|
||||
String other = req.getParameter(ThreadedHTMLRenderer.PARAM_PROFILE_OTHER);
|
||||
|
||||
Properties opts = new Properties();
|
||||
if (!empty(name))
|
||||
opts.setProperty(BlogInfo.NAME, name.trim());
|
||||
if (!empty(desc))
|
||||
opts.setProperty(BlogInfo.DESCRIPTION, desc.trim());
|
||||
if (!empty(url))
|
||||
opts.setProperty(BlogInfo.CONTACT_URL, url.trim());
|
||||
if (!empty(other)) {
|
||||
StringBuffer key = new StringBuffer();
|
||||
StringBuffer val = null;
|
||||
for (int i = 0; i < other.length(); i++) {
|
||||
char c = other.charAt(i);
|
||||
if ( (c == ':') || (c == '=') ) {
|
||||
if (val != null) {
|
||||
val.append(c);
|
||||
} else {
|
||||
val = new StringBuffer();
|
||||
}
|
||||
} else if ( (c == '\n') || (c == '\r') ) {
|
||||
String k = key.toString().trim();
|
||||
String v = (val != null ? val.toString().trim() : "");
|
||||
if ( (k.length() > 0) && (v.length() > 0) ) {
|
||||
opts.setProperty(k, v);
|
||||
}
|
||||
key.setLength(0);
|
||||
val = null;
|
||||
} else if (val != null) {
|
||||
val.append(c);
|
||||
} else {
|
||||
key.append(c);
|
||||
}
|
||||
}
|
||||
// now finish the last of it
|
||||
String k = key.toString().trim();
|
||||
String v = (val != null ? val.toString().trim() : "");
|
||||
if ( (k.length() > 0) && (v.length() > 0) ) {
|
||||
opts.setProperty(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
String pass0 = req.getParameter("password");
|
||||
String pass1 = req.getParameter("passwordConfirm");
|
||||
String oldPass = req.getParameter("oldPassword");
|
||||
|
||||
if ( (pass0 != null) && (pass1 != null) && (pass0.equals(pass1)) ) {
|
||||
BlogManager.instance().changePasswrd(user, oldPass, pass0, pass1);
|
||||
}
|
||||
|
||||
boolean updated = BlogManager.instance().updateMetadata(user, user.getBlog(), opts);
|
||||
}
|
||||
|
||||
private User handleRegister(User user, HttpServletRequest req) {
|
||||
String l = req.getParameter("login");
|
||||
String p = req.getParameter("password");
|
||||
String name = req.getParameter("accountName");
|
||||
String desc = req.getParameter("description");
|
||||
String contactURL = req.getParameter("url");
|
||||
String regPass = req.getParameter("registrationPass");
|
||||
String action = req.getParameter("action");
|
||||
|
||||
if ( (action != null) && ("Register".equals(action)) && !empty(l) ) {
|
||||
return BlogManager.instance().register(l, p, regPass, name, desc, contactURL);
|
||||
} else {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAdmin(User user, HttpServletRequest req) throws IOException {
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
String action = req.getParameter("action");
|
||||
if ( (action != null) && ("Save config".equals(action)) ) {
|
||||
boolean wantSingle = !empty(req, "singleuser");
|
||||
String defaultUser = req.getParameter("defaultUser");
|
||||
String defaultPass = req.getParameter("defaultPass");
|
||||
String regPass = req.getParameter("regpass");
|
||||
String remotePass = req.getParameter("remotepass");
|
||||
String proxyHost = req.getParameter("proxyhost");
|
||||
String proxyPort = req.getParameter("proxyport");
|
||||
|
||||
// default user cannot be empty, but the rest can be blank
|
||||
if ( (!empty(defaultUser)) && (defaultPass != null) && (regPass != null) && (remotePass != null) &&
|
||||
(proxyHost != null) && (proxyPort != null) ) {
|
||||
int port = 4444;
|
||||
try { port = Integer.parseInt(proxyPort); } catch (NumberFormatException nfe) {}
|
||||
BlogManager.instance().configure(regPass, remotePass, null, null, proxyHost, port, wantSingle,
|
||||
null, defaultUser, defaultPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void render(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws ServletException, IOException {
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
int numThreads = 10;
|
||||
int threadOffset = getOffset(req);
|
||||
if (threadOffset == -1) {
|
||||
threadOffset = index.getRootCount() - numThreads;
|
||||
}
|
||||
if (threadOffset < 0) {
|
||||
threadOffset = 0;
|
||||
}
|
||||
|
||||
BlogURI visibleEntry = getVisible(req);
|
||||
|
||||
int offset = 0;
|
||||
if ( empty(req, ThreadedHTMLRenderer.PARAM_OFFSET) && (visibleEntry != null) ) {
|
||||
// we're on a permalink, so jump the tree to the given thread
|
||||
threadOffset = index.getRoot(visibleEntry);
|
||||
if (threadOffset < 0)
|
||||
threadOffset = 0;
|
||||
}
|
||||
|
||||
renderBegin(user, req, out, index);
|
||||
renderNavBar(user, req, out, index);
|
||||
renderControlBar(user, req, out, index);
|
||||
renderServletDetails(user, req, out, index, threadOffset, visibleEntry, archive);
|
||||
renderEnd(user, req, out, index);
|
||||
}
|
||||
|
||||
protected void renderBegin(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
out.write("<html>\n<head><title>" + getTitle() + "</title>\n" + BEGIN_HTML);
|
||||
}
|
||||
protected void renderNavBar(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
//out.write("<tr class=\"topNav\"><td class=\"topNav_user\" colspan=\"2\" nowrap=\"true\">\n");
|
||||
out.write("<tr class=\"topNav\"><td colspan=\"3\" nowrap=\"true\"><span class=\"topNav_user\">\n");
|
||||
out.write("<!-- nav bar begin -->\n");
|
||||
if (user.getAuthenticated() && (user.getBlog() != null) ) {
|
||||
out.write("Logged in as <a href=\"" + getProfileLink(req, user.getBlog()) + "\" title=\"Edit your profile\">");
|
||||
out.write(user.getUsername());
|
||||
out.write("</a>\n");
|
||||
out.write("(<a href=\"switchuser.jsp\" title=\"Log in as another user\">switch</a>)\n");
|
||||
out.write("<a href=\"" + getPostURI() + "\" title=\"Post a new thread\">Post a new thread</a>\n");
|
||||
out.write("<a href=\"addresses.jsp\" title=\"View your addressbook\">Addressbook</a>\n");
|
||||
} else {
|
||||
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">\n");
|
||||
writeAuthActionFields(out);
|
||||
out.write("Login: <input type=\"text\" name=\"login\" />\n");
|
||||
out.write("Password: <input type=\"password\" name=\"password\" />\n");
|
||||
out.write("<input type=\"submit\" name=\"action\" value=\"Login\" /></form>\n");
|
||||
}
|
||||
//out.write("</td><td class=\"topNav_admin\">\n");
|
||||
out.write("</span><span class=\"topNav_admin\">\n");
|
||||
out.write("<a href=\"about.html\" title=\"Basic Syndie info\">About</a> ");
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
out.write("<a href=\"" + getSyndicateLink(user, null) + "\" title=\"Syndicate data between other Syndie nodes\">Syndicate</a>\n");
|
||||
out.write("<a href=\"importfeed.jsp\" title=\"Import RSS/Atom data\">Import RSS/Atom</a>\n");
|
||||
out.write("<a href=\"admin.jsp\" title=\"Configure this Syndie node\">Admin</a>\n");
|
||||
}
|
||||
out.write("</span><!-- nav bar end -->\n</td></tr>\n");
|
||||
}
|
||||
|
||||
protected String getSyndicateLink(User user, String location) {
|
||||
if (location != null)
|
||||
return "syndicate.jsp?" + SyndicateServlet.PARAM_LOCATION + "=" + location;
|
||||
return "syndicate.jsp";
|
||||
}
|
||||
|
||||
protected static final ArrayList SKIP_TAGS = new ArrayList();
|
||||
static {
|
||||
SKIP_TAGS.add("action");
|
||||
SKIP_TAGS.add("filter");
|
||||
// post and visible are skipped since we aren't good at filtering by tag when the offset will
|
||||
// skip around randomly. at least, not yet.
|
||||
SKIP_TAGS.add("visible");
|
||||
//SKIP_TAGS.add("post");
|
||||
//SKIP_TAGS.add("thread");
|
||||
SKIP_TAGS.add("offset"); // if we are adjusting the filter, ignore the previous offset
|
||||
SKIP_TAGS.add("addLocation");
|
||||
SKIP_TAGS.add("addGroup");
|
||||
SKIP_TAGS.add("login");
|
||||
SKIP_TAGS.add("password");
|
||||
}
|
||||
|
||||
private static final String CONTROL_TARGET = "threads.jsp";
|
||||
protected String getControlTarget() { return CONTROL_TARGET; }
|
||||
protected String getPostURI() { return "post.jsp"; }
|
||||
|
||||
protected void renderControlBar(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
out.write("<form action=\"");
|
||||
//out.write(req.getRequestURI());
|
||||
out.write(getControlTarget());
|
||||
out.write("\" method=\"GET\">\n");
|
||||
String tags = "";
|
||||
String author = "";
|
||||
Enumeration params = req.getParameterNames();
|
||||
while (params.hasMoreElements()) {
|
||||
String param = (String)params.nextElement();
|
||||
String val = req.getParameter(param);
|
||||
if (ThreadedHTMLRenderer.PARAM_TAGS.equals(param)) {
|
||||
tags = val;
|
||||
} else if (ThreadedHTMLRenderer.PARAM_AUTHOR.equals(param)) {
|
||||
author = val;
|
||||
} else if (SKIP_TAGS.contains(param)) {
|
||||
// skip
|
||||
} else if (param.length() <= 0) {
|
||||
// skip
|
||||
} else {
|
||||
out.write("<input type=\"hidden\" name=\"" + param + "\" value=\"" + val + "\" />\n");
|
||||
}
|
||||
}
|
||||
out.write("<tr class=\"controlBar\"><td colspan=\"2\" width=\"99%\">\n");
|
||||
out.write("<!-- control bar begin -->\n");
|
||||
out.write("Filter: <select name=\"" + ThreadedHTMLRenderer.PARAM_AUTHOR + "\">\n");
|
||||
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
TreeSet names = new TreeSet(db.getNames());
|
||||
out.write("<option value=\"\">Any authors</option>\n");
|
||||
if (user.getBlog() != null) {
|
||||
if ( (author != null) && (author.equals(user.getBlog().toBase64())) )
|
||||
out.write("<option value=\"" + user.getBlog().toBase64() + "\" selected=\"true\">Threads you posted in</option>\n");
|
||||
else
|
||||
out.write("<option value=\"" + user.getBlog().toBase64() + "\">Threads you posted in</option>\n");
|
||||
}
|
||||
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
String name = (String) iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if ("syndieblog".equals(pn.getProtocol())) {
|
||||
if ( (author != null) && (author.equals(pn.getLocation())) )
|
||||
out.write("<option value=\"" + pn.getLocation() + "\" selected=\"true\">Threads " + name + " posted in</option>\n");
|
||||
else
|
||||
out.write("<option value=\"" + pn.getLocation() + "\">Threads " + name + " posted in</option>\n");
|
||||
}
|
||||
}
|
||||
out.write("</select>\n");
|
||||
|
||||
out.write("Tags: <input type=\"text\" name=\"" + ThreadedHTMLRenderer.PARAM_TAGS + "\" size=\"10\" value=\"" + tags + "\" />\n");
|
||||
|
||||
out.write("<input type=\"submit\" name=\"action\" value=\"Go\" />\n");
|
||||
out.write("</td><td class=\"controlBarRight\" width=\"1%\"><a href=\"#threads\" title=\"Jump to the thread navigation\">Threads</a></td>\n");
|
||||
out.write("<!-- control bar end -->\n");
|
||||
out.write("</tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
protected abstract void renderServletDetails(User user, HttpServletRequest req, PrintWriter out,
|
||||
ThreadIndex index, int threadOffset, BlogURI visibleEntry,
|
||||
Archive archive) throws IOException;
|
||||
|
||||
protected static final int getOffset(HttpServletRequest req) {
|
||||
String off = req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET);
|
||||
try {
|
||||
return Integer.parseInt(off);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
protected static final BlogURI getVisible(HttpServletRequest req) {
|
||||
return getAsBlogURI(req.getParameter(ThreadedHTMLRenderer.PARAM_VISIBLE));
|
||||
}
|
||||
protected static final BlogURI getAsBlogURI(String uri) {
|
||||
if (uri != null) {
|
||||
int split = uri.indexOf('/');
|
||||
if ( (split <= 0) || (split + 1 >= uri.length()) )
|
||||
return null;
|
||||
String blog = uri.substring(0, split);
|
||||
String id = uri.substring(split+1);
|
||||
try {
|
||||
Hash hash = new Hash();
|
||||
hash.fromBase64(blog);
|
||||
long msgId = Long.parseLong(id);
|
||||
if (msgId > 0)
|
||||
return new BlogURI(hash, msgId);
|
||||
} catch (DataFormatException dfe) {
|
||||
return null;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected String trim(String orig, int maxLen) {
|
||||
if ( (orig == null) || (orig.length() <= maxLen) )
|
||||
return orig;
|
||||
return orig.substring(0, maxLen) + "...";
|
||||
}
|
||||
|
||||
protected static final boolean empty(HttpServletRequest req, String param) {
|
||||
String val = req.getParameter(param);
|
||||
return (val == null) || (val.trim().length() <= 0);
|
||||
}
|
||||
|
||||
protected static final boolean empty(String val) {
|
||||
return (val == null) || (val.trim().length() <= 0);
|
||||
}
|
||||
|
||||
protected String getExpandLink(HttpServletRequest req, ThreadNode node) {
|
||||
return getExpandLink(node, req.getRequestURI(), req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
|
||||
}
|
||||
protected static String getExpandLink(ThreadNode node, String uri, String viewPost, String viewThread,
|
||||
String offset, String tags, String author) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
buf.append('?');
|
||||
// expand node == let one of node's children be visible
|
||||
if (node.getChildCount() > 0) {
|
||||
ThreadNode child = node.getChild(0);
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=');
|
||||
buf.append(child.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(child.getEntry().getEntryId()).append('&');
|
||||
}
|
||||
|
||||
if (!empty(viewPost))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(viewPost).append('&');
|
||||
else if (!empty(viewThread))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
|
||||
|
||||
if (!empty(offset))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(author))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
protected String getCollapseLink(HttpServletRequest req, ThreadNode node) {
|
||||
return getCollapseLink(node, req.getRequestURI(),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
|
||||
}
|
||||
|
||||
protected String getCollapseLink(ThreadNode node, String uri, String viewPost, String viewThread,
|
||||
String offset, String tags, String author) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
// collapse node == let the node be visible
|
||||
buf.append('?').append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
|
||||
if (!empty(viewPost))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(viewPost).append('&');
|
||||
else if (!empty(viewThread))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
|
||||
|
||||
if (!empty(offset))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(author))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
protected String getProfileLink(HttpServletRequest req, Hash author) {
|
||||
return getProfileLink(author);
|
||||
}
|
||||
protected String getProfileLink(Hash author) { return ThreadedHTMLRenderer.buildProfileURL(author); }
|
||||
|
||||
protected String getAddToGroupLink(HttpServletRequest req, Hash author, User user, String group) {
|
||||
return getAddToGroupLink(user, author, group, req.getRequestURI(),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VISIBLE),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
|
||||
}
|
||||
protected String getAddToGroupLink(User user, Hash author, String group, String uri, String visible,
|
||||
String viewPost, String viewThread, String offset, String tags, String filteredAuthor) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
buf.append('?');
|
||||
if (!empty(visible))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=').append(visible).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_ADD_TO_GROUP_LOCATION).append('=').append(author.toBase64()).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_ADD_TO_GROUP_NAME).append('=').append(group).append('&');
|
||||
|
||||
if (!empty(viewPost))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(viewPost).append('&');
|
||||
else if (!empty(viewThread))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
|
||||
|
||||
if (!empty(offset))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(filteredAuthor))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(filteredAuthor).append('&');
|
||||
|
||||
addAuthActionParams(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
protected String getRemoveFromGroupLink(User user, String name, String group, String uri, String visible,
|
||||
String viewPost, String viewThread, String offset, String tags, String filteredAuthor) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
buf.append('?');
|
||||
if (!empty(visible))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=').append(visible).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_REMOVE_FROM_GROUP_NAME).append('=').append(name).append('&');
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_REMOVE_FROM_GROUP).append('=').append(group).append('&');
|
||||
|
||||
if (!empty(viewPost))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_POST).append('=').append(viewPost).append('&');
|
||||
else if (!empty(viewThread))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
|
||||
|
||||
if (!empty(offset))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(filteredAuthor))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(filteredAuthor).append('&');
|
||||
|
||||
addAuthActionParams(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
protected String getViewPostLink(HttpServletRequest req, ThreadNode node, User user, boolean isPermalink) {
|
||||
return ThreadedHTMLRenderer.getViewPostLink(req.getRequestURI(), node, user, isPermalink,
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
|
||||
}
|
||||
protected String getViewThreadLink(HttpServletRequest req, ThreadNode node, User user) {
|
||||
return getViewThreadLink(req.getRequestURI(), node, user,
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
|
||||
}
|
||||
protected static String getViewThreadLink(String uri, ThreadNode node, User user, String offset,
|
||||
String tags, String author) {
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append(uri);
|
||||
if (node.getChildCount() > 0) {
|
||||
buf.append('?').append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=');
|
||||
ThreadNode child = node.getChild(0);
|
||||
buf.append(child.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(child.getEntry().getEntryId()).append('&');
|
||||
} else {
|
||||
buf.append('?').append(ThreadedHTMLRenderer.PARAM_VISIBLE).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
}
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_VIEW_THREAD).append('=');
|
||||
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
|
||||
buf.append(node.getEntry().getEntryId()).append('&');
|
||||
|
||||
if (!empty(offset))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_OFFSET).append('=').append(offset).append('&');
|
||||
|
||||
if (!empty(tags))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
|
||||
|
||||
if (!empty(author))
|
||||
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
|
||||
|
||||
buf.append("#").append(node.getEntry().toString());
|
||||
return buf.toString();
|
||||
}
|
||||
protected String getFilterByTagLink(HttpServletRequest req, ThreadNode node, User user, String tag, String author) {
|
||||
return ThreadedHTMLRenderer.getFilterByTagLink(req.getRequestURI(), node, user, tag, author);
|
||||
}
|
||||
protected String getNavLink(HttpServletRequest req, int offset) {
|
||||
return ThreadedHTMLRenderer.getNavLink(req.getRequestURI(),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
|
||||
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR),
|
||||
offset);
|
||||
}
|
||||
|
||||
protected void renderEnd(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
out.write(END_HTML);
|
||||
}
|
||||
|
||||
protected Collection getFilteredTags(HttpServletRequest req) {
|
||||
String tags = req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS);
|
||||
if (tags != null) {
|
||||
StringTokenizer tok = new StringTokenizer(tags, "\n\t ");
|
||||
ArrayList rv = new ArrayList();
|
||||
while (tok.hasMoreTokens()) {
|
||||
String tag = tok.nextToken().trim();
|
||||
if (tag.length() > 0)
|
||||
rv.add(tag);
|
||||
}
|
||||
return rv;
|
||||
} else {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
protected Collection getFilteredAuthors(HttpServletRequest req) {
|
||||
String authors = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
|
||||
if (authors != null) {
|
||||
StringTokenizer tok = new StringTokenizer(authors, "\n\t ");
|
||||
ArrayList rv = new ArrayList();
|
||||
while (tok.hasMoreTokens()) {
|
||||
try {
|
||||
Hash h = new Hash();
|
||||
h.fromBase64(tok.nextToken().trim());
|
||||
rv.add(h);
|
||||
} catch (DataFormatException dfe) {}
|
||||
}
|
||||
return rv;
|
||||
} else {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BEGIN_HTML = "<style>\n" +
|
||||
".overallTable {\n" +
|
||||
" border-spacing: 0px;\n" +
|
||||
" border-width: 0px;\n" +
|
||||
" border: 0px;\n" +
|
||||
" margin: 0px;\n" +
|
||||
" padding: 0px;\n" +
|
||||
"}\n" +
|
||||
".topNav {\n" +
|
||||
" background-color: #BBBBBB;\n" +
|
||||
"}\n" +
|
||||
".topNav_user {\n" +
|
||||
" text-align: left;\n" +
|
||||
" float: left;\n" +
|
||||
" display: inline;\n" +
|
||||
"}\n" +
|
||||
".topNav_admin {\n" +
|
||||
" text-align: right;\n" +
|
||||
" float: right;\n" +
|
||||
" margin: 0 5px 0 0;\n" +
|
||||
" display: inline;\n" +
|
||||
"}\n" +
|
||||
".controlBar {\n" +
|
||||
" background-color: #BBBBBB;\n" +
|
||||
"}\n" +
|
||||
".controlBarRight {\n" +
|
||||
" text-align: right;\n" +
|
||||
"}\n" +
|
||||
".threadEven {\n" +
|
||||
" background-color: #FFFFFF;\n" +
|
||||
" white-space: nowrap;\n" +
|
||||
"}\n" +
|
||||
".threadOdd {\n" +
|
||||
" background-color: #EEEEEE;\n" +
|
||||
" white-space: nowrap;\n" +
|
||||
"}\n" +
|
||||
".threadLeft {\n" +
|
||||
" text-align: left;\n" +
|
||||
" align: left;\n" +
|
||||
"}\n" +
|
||||
".threadRight {\n" +
|
||||
" text-align: right;\n" +
|
||||
"}\n" +
|
||||
".threadNav {\n" +
|
||||
" background-color: #BBBBBB;\n" +
|
||||
"}\n" +
|
||||
".threadNavRight {\n" +
|
||||
" text-align: right;\n" +
|
||||
"}\n" +
|
||||
".postMeta {\n" +
|
||||
" background-color: #BBBBFF;\n" +
|
||||
"}\n" +
|
||||
".postMetaSubject {\n" +
|
||||
" text-align: left;\n" +
|
||||
"}\n" +
|
||||
".postMetaLink {\n" +
|
||||
" text-align: right;\n" +
|
||||
"}\n" +
|
||||
".postDetails {\n" +
|
||||
" background-color: #DDDDFF;\n" +
|
||||
"}\n" +
|
||||
".postReply {\n" +
|
||||
" background-color: #BBBBFF;\n" +
|
||||
"}\n" +
|
||||
".postReplyText {\n" +
|
||||
" background-color: #BBBBFF;\n" +
|
||||
"}\n" +
|
||||
".postReplyOptions {\n" +
|
||||
" background-color: #BBBBFF;\n" +
|
||||
"}\n" +
|
||||
"</style>\n" +
|
||||
"<link href=\"style.jsp\" rel=\"stylesheet\" type=\"text/css\" >\n" +
|
||||
"<link href=\"rss.jsp\" rel=\"alternate\" type=\"application/rss+xml\" >\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
"<span style=\"display: none\"><a href=\"#bodySubject\">Jump to the beginning of the first post rendered, if any</a>\n" +
|
||||
"<a href=\"#threads\">Jump to the thread navigation</a>\n</span>\n" +
|
||||
"<table border=\"0\" width=\"100%\" class=\"overallTable\">\n";
|
||||
|
||||
private static final String END_HTML = "</table>\n" +
|
||||
"</body>\n";
|
||||
|
||||
protected String getTitle() { return "Syndie"; }
|
||||
|
||||
protected static class TreeRenderState {
|
||||
private int _rowsWritten;
|
||||
private int _rowsSkipped;
|
||||
private List _ignored;
|
||||
public TreeRenderState(List ignored) {
|
||||
_rowsWritten = 0;
|
||||
_rowsSkipped = 0;
|
||||
_ignored = ignored;
|
||||
}
|
||||
public int getRowsWritten() { return _rowsWritten; }
|
||||
public void incrementRowsWritten() { _rowsWritten++; }
|
||||
public int getRowsSkipped() { return _rowsSkipped; }
|
||||
public void incrementRowsSkipped() { _rowsSkipped++; }
|
||||
public List getIgnoredAuthors() { return _ignored; }
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,16 @@ public class ExportServlet extends HttpServlet {
|
||||
export(req, resp);
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
export(req, resp);
|
||||
}
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
export(req, resp);
|
||||
}
|
||||
public void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
export(req, resp);
|
||||
}
|
||||
|
||||
public static void export(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
try {
|
||||
doExport(req, resp);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Confirm page before hitting a remote site
|
||||
*
|
||||
*/
|
||||
public class ExternalLinkServlet extends BaseServlet {
|
||||
protected String getTitle() { return "Syndie :: External link"; }
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
String b64Schema = req.getParameter("schema");
|
||||
String b64Location = req.getParameter("location");
|
||||
if ( (b64Schema == null) || (b64Schema.trim().length() <= 0) ||
|
||||
(b64Location == null) || (b64Location.trim().length() <= 0) ) {
|
||||
out.write("<tr><td colspan=\"3\">No location specified</td></tr>\n");
|
||||
} else {
|
||||
byte loc[] = Base64.decode(b64Location);
|
||||
if ( (loc == null) || (loc.length <= 0) ) {
|
||||
out.write("<tr><td colspan=\"3\">Invalid location specified</td></tr>\n");
|
||||
} else {
|
||||
String location = DataHelper.getUTF8(loc);
|
||||
out.write("<tr><td colspan=\"3\">Are you sure you want to go to <a href=\"");
|
||||
out.write(HTMLRenderer.sanitizeTagParam(location));
|
||||
out.write("\" title=\"Link to an external site\">");
|
||||
out.write(HTMLRenderer.sanitizeString(location));
|
||||
out.write("</a></td></tr>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
158
apps/syndie/java/src/net/i2p/syndie/web/ImportFeedServlet.java
Normal file
@@ -0,0 +1,158 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Schedule the import of atom/rss feeds
|
||||
*
|
||||
* <p><h3>todo:</h3>
|
||||
* <p>caching (eepget should do it)
|
||||
* <p>enclosures support (requires cvs rome)
|
||||
* <p>syndie.sucker.minHistory/maxHistory used to roll over the history file?
|
||||
* <p>configurable update period
|
||||
*
|
||||
*/
|
||||
public class ImportFeedServlet extends BaseServlet {
|
||||
protected String getTitle() { return "Syndie :: Import feed"; }
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
|
||||
if (!BlogManager.instance().authorizeRemote(user)) {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_rssMsgErr\">You are not authorized for remote access.</span></td></tr>\n");
|
||||
} else {
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
|
||||
String url=req.getParameter("url");
|
||||
if (url != null)
|
||||
url = url.trim();
|
||||
String blog=req.getParameter("blog");
|
||||
if (blog != null)
|
||||
blog=blog.trim();
|
||||
String tagPrefix = req.getParameter("tagprefix");
|
||||
if (tagPrefix != null)
|
||||
tagPrefix=tagPrefix.trim();
|
||||
String action = req.getParameter("action");
|
||||
if ( (action != null) && ("Add".equals(action)) ) {
|
||||
if(url==null || blog==null || tagPrefix==null) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">Please fill in all fields</span><br />\n");
|
||||
} else {
|
||||
boolean ret = BlogManager.instance().addRssFeed(url, blog, tagPrefix);
|
||||
if (!ret) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">addRssFeed failure.</span>");
|
||||
} else {
|
||||
out.write("<span class=\"b_rssImportMsgOk\">RSS feed added.</span>");
|
||||
}
|
||||
}
|
||||
} else if ( (action != null) && ("Change".equals(action)) ) {
|
||||
String lastUrl=req.getParameter("lasturl");
|
||||
String lastBlog=req.getParameter("lastblog");
|
||||
String lastTagPrefix=req.getParameter("lasttagprefix");
|
||||
|
||||
if (url == null || blog == null || tagPrefix == null ||
|
||||
lastUrl == null || lastBlog == null || lastTagPrefix == null) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">error, some fields were empty.</span><br />");
|
||||
} else {
|
||||
boolean ret = BlogManager.instance().deleteRssFeed(lastUrl,lastBlog,lastTagPrefix);
|
||||
if (!ret) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">Could not delete while attempting to change.</span>");
|
||||
} else {
|
||||
ret = BlogManager.instance().addRssFeed(url,blog,tagPrefix);
|
||||
if (!ret) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">Could not add while attempting to change.</span>");
|
||||
} else {
|
||||
out.write("<span class=\"b_rssImportMsgOk\">Ok, changed successfully.</span>");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ( (action != null) && ("Delete".equals(action)) ) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">Delete some thing</span><br />");
|
||||
if (url == null || blog == null || tagPrefix == null) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">error, some fields were empty.</span><br />");
|
||||
} else {
|
||||
boolean ret = BlogManager.instance().deleteRssFeed(url,blog,tagPrefix);
|
||||
if (!ret) {
|
||||
out.write("<span class=\"b_rssImportMsgErr\">error, could not delete.</span>");
|
||||
} else {
|
||||
out.write("<span class=\"b_rssImportMsgOk\">ok, deleted successfully.</span>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String blogStr = user.getBlogStr();
|
||||
if (blogStr == null)
|
||||
blogStr="";
|
||||
|
||||
out.write("<p>Here you can add RSS feeds that will be periodically polled and added to your syndie. </p>");
|
||||
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
out.write("RSS URL. (e.g. http://tracker.postman.i2p/rss.php)<br />\n");
|
||||
out.write("<em><span class=\"b_rssImportField\">url:</span></em> <input class=\"b_rssImportField\" type=\"text\" size=\"50\" name=\"url\" /><br />\n");
|
||||
out.write("Blog hash to which the RSS entries will get posted, defaults to the one you're logged in to.<br />\n");
|
||||
out.write("<em><span class=\"b_rssImportField\">blog:</span></em> <input class=\"b_rssImportField\" type=\"text\" value=\"");
|
||||
out.write(blogStr);
|
||||
out.write("\" size=\"20\" name=\"blog\" /><br />\n");
|
||||
out.write("This will be prepended to any tags that the RSS feed contains. (e.g. feed.tracker)<br />\n");
|
||||
out.write("<em><span class=\"b_rssImportField\">tagprefix:</span></em>\n");
|
||||
out.write("<input class=\"b_rssImportField\" type=\"text\" value=\"feed\" size=\"20\" name=\"tagprefix\" /><br />\n");
|
||||
out.write("<input class=\"b_rssImportSubmit\" type=\"submit\" name=\"action\" value=\"Add\" />\n");
|
||||
out.write("<input class=\"b_rssImportCancel\" type=\"reset\" value=\"Cancel\" />\n");
|
||||
out.write("</form>\n");
|
||||
|
||||
List feedList = BlogManager.instance().getRssFeeds();
|
||||
if (feedList.size()>0) {
|
||||
out.write("<hr /><h3>Subscriptions:</h3><br />\n");
|
||||
out.write("<table border=\"0\" width=\"100%\" class=\"b_rss\">\n");
|
||||
out.write("<tr class=\"b_rssHeader\">\n");
|
||||
out.write("<td class=\"b_rssHeader\"><em class=\"b_rssHeader\">Url</em></td>\n");
|
||||
out.write("<td class=\"b_rssHeader\"><em class=\"b_rssHeader\">Blog</em></td>\n");
|
||||
out.write("<td class=\"b_rssHeader\"><em class=\"b_rssHeader\">TagPrefix</em></td>\n");
|
||||
out.write("<td class=\"b_rssHeader\"> </td></tr>\n");
|
||||
|
||||
Iterator iter = feedList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
String fields[] = (String[])iter.next();
|
||||
url = fields[0];
|
||||
blog = fields[1];
|
||||
tagPrefix = fields[2];
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
|
||||
buf.append("<tr class=\"b_rssDetail\"><form action=\"" + req.getRequestURI() + "\" method=\"POST\">");
|
||||
writeAuthActionFields(out);
|
||||
buf.append("<input type=\"hidden\" name=\"lasturl\" value=\"").append(url).append("\" />");
|
||||
buf.append("<input type=\"hidden\" name=\"lastblog\" value=\"").append(blog).append("\" />");
|
||||
buf.append("<input type=\"hidden\" name=\"lasttagprefix\" value=\"").append(tagPrefix).append("\" />");
|
||||
|
||||
buf.append("<td class=\"b_rssUrl\"><input class=\"b_rssUrl\" type=\"text\" size=\"50\" name=\"url\" value=\"").append(url).append("\" /></td>");
|
||||
buf.append("<td class=\"b_rssBlog\"><input class=\"b_rssBlog\" type=\"text\" size=\"20\" name=\"blog\" value=\"").append(blog).append("\" /></td>");
|
||||
buf.append("<td class=\"b_rssPrefix\"><input class=\"b_rssPrefix\" type=\"text\" size=\"20\" name=\"tagprefix\" value=\"").append(tagPrefix).append("\" /></td>");
|
||||
buf.append("<td class=\"b_rssDetail\" nowrap=\"nowrap\">");
|
||||
|
||||
buf.append("<input class=\"b_rssChange\" type=\"submit\" name=\"action\" value=\"Change\" />");
|
||||
buf.append("<input class=\"b_rssDelete\" type=\"submit\" name=\"action\" value=\"Delete\" />");
|
||||
|
||||
buf.append("</td></form></tr>");
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
}
|
||||
|
||||
out.write("</table>\n");
|
||||
} // end iterating over feeds
|
||||
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,6 +163,9 @@ public class PostBean {
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
/** until we have a good filtering/preferences system, lets try to keep the content small */
|
||||
private static final int MAX_SIZE = 256*1024;
|
||||
|
||||
private void cacheAttachments() throws IOException {
|
||||
File postCacheDir = new File(BlogManager.instance().getTempDir(), _user.getBlog().toBase64());
|
||||
if (!postCacheDir.exists())
|
||||
@@ -177,10 +180,14 @@ public class PostBean {
|
||||
o.write(buf, 0, read);
|
||||
o.close();
|
||||
in.close();
|
||||
_localFiles.add(f);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Caching attachment " + i + " temporarily in "
|
||||
+ f.getAbsolutePath() + " w/ " + f.length() + "bytes");
|
||||
if (f.length() > MAX_SIZE) {
|
||||
_log.error("Refusing to post the attachment, because it is too big: " + f.length());
|
||||
} else {
|
||||
_localFiles.add(f);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Caching attachment " + i + " temporarily in "
|
||||
+ f.getAbsolutePath() + " w/ " + f.length() + "bytes");
|
||||
}
|
||||
}
|
||||
_fileStreams.clear();
|
||||
}
|
||||
|
||||
295
apps/syndie/java/src/net/i2p/syndie/web/PostServlet.java
Normal file
@@ -0,0 +1,295 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.mortbay.servlet.MultiPartRequest;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Post and preview form
|
||||
*
|
||||
*/
|
||||
public class PostServlet extends BaseServlet {
|
||||
public static final String PARAM_ACTION = "action";
|
||||
public static final String ACTION_CONFIRM = "confirm";
|
||||
|
||||
public static final String PARAM_SUBJECT = "entrysubject";
|
||||
public static final String PARAM_TAGS = "entrytags";
|
||||
public static final String PARAM_INCLUDENAMES = "includenames";
|
||||
public static final String PARAM_TEXT = "entrytext";
|
||||
public static final String PARAM_HEADERS = "entryheaders";
|
||||
|
||||
public static final String PARAM_PARENT = "parentURI";
|
||||
public static final String PARAM_IN_NEW_THREAD = "replyInNewThread";
|
||||
public static final String PARAM_REFUSE_REPLIES = "refuseReplies";
|
||||
|
||||
public static final String PARAM_REMOTE_ARCHIVE = "archive";
|
||||
|
||||
private static final String ATTR_POST_BEAN = "post";
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
if (!user.getAuthenticated()) {
|
||||
out.write("<tr><td colspan=\"3\">You must be logged in to post</td></tr>\n");
|
||||
} else {
|
||||
PostBean post = getPostBean(user, req);
|
||||
String action = req.getParameter(PARAM_ACTION);
|
||||
if (!empty(action) && ACTION_CONFIRM.equals(action)) {
|
||||
postEntry(user, req, archive, post, out);
|
||||
} else {
|
||||
String contentType = req.getContentType();
|
||||
if (!empty(contentType) && (contentType.indexOf("boundary=") != -1)) {
|
||||
previewPostedData(user, req, archive, contentType, post, out);
|
||||
} else {
|
||||
displayNewForm(user, req, post, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void previewPostedData(User user, HttpServletRequest rawRequest, Archive archive, String contentType, PostBean post, PrintWriter out) throws IOException {
|
||||
MultiPartRequest req = new MultiPartRequest(rawRequest);
|
||||
|
||||
if (!authAction(req.getString(PARAM_AUTH_ACTION))) {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgErro\">Invalid form submission... stale data?</span></td></tr>");
|
||||
return;
|
||||
}
|
||||
|
||||
// not confirmed but they posted stuff... gobble up what they give
|
||||
// and display it as a prview (then we show the confirm form
|
||||
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
|
||||
boolean inNewThread = getInNewThread(req.getString(PARAM_IN_NEW_THREAD));
|
||||
boolean refuseReplies = getRefuseReplies(req.getString(PARAM_REFUSE_REPLIES));
|
||||
|
||||
String entrySubject = req.getString(PARAM_SUBJECT);
|
||||
String entryTags = req.getString(PARAM_TAGS);
|
||||
String entryText = req.getString(PARAM_TEXT);
|
||||
String entryHeaders = req.getString(PARAM_HEADERS);
|
||||
String style = ""; //req.getString("style");
|
||||
if ( (style != null) && (style.trim().length() > 0) ) {
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
}
|
||||
String replyTo = req.getString(PARAM_PARENT);
|
||||
if ( (replyTo != null) && (replyTo.trim().length() > 0) ) {
|
||||
byte r[] = Base64.decode(replyTo);
|
||||
if (r != null) {
|
||||
replyTo = new String(r, "UTF-8");
|
||||
if (!replyTo.startsWith("entry://") && !replyTo.startsWith("blog://"))
|
||||
replyTo = "entry://" + replyTo;
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_IN_REPLY_TO + ": " + replyTo;
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": " + replyTo;
|
||||
} else {
|
||||
replyTo = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (entryHeaders == null) || (entryHeaders.trim().length() <= 0) )
|
||||
entryHeaders = ThreadedHTMLRenderer.HEADER_FORCE_NEW_THREAD + ": " + inNewThread + '\n' +
|
||||
ThreadedHTMLRenderer.HEADER_REFUSE_REPLIES + ": " + refuseReplies;
|
||||
else
|
||||
entryHeaders = entryHeaders.trim() + '\n' +
|
||||
ThreadedHTMLRenderer.HEADER_FORCE_NEW_THREAD + ": " + inNewThread + '\n' +
|
||||
ThreadedHTMLRenderer.HEADER_REFUSE_REPLIES + ": " + refuseReplies;
|
||||
|
||||
String includeNames = req.getString(PARAM_INCLUDENAMES);
|
||||
if ( (includeNames != null) && (includeNames.trim().length() > 0) ) {
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
if (entryHeaders == null) entryHeaders = "";
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
if ( (pn != null) && (pn.getIsPublic()) ) {
|
||||
entryHeaders = entryHeaders.trim() + '\n' + HTMLRenderer.HEADER_PETNAME + ": " +
|
||||
pn.getName() + "\t" + pn.getNetwork() + "\t" + pn.getProtocol() + "\t" + pn.getLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post.setSubject(entrySubject);
|
||||
post.setTags(entryTags);
|
||||
post.setText(entryText);
|
||||
post.setHeaders(entryHeaders);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
String filename = req.getFilename("entryfile" + i);
|
||||
if ( (filename != null) && (filename.trim().length() > 0) ) {
|
||||
Hashtable params = req.getParams("entryfile" + i);
|
||||
String type = "application/octet-stream";
|
||||
for (Iterator iter = params.keySet().iterator(); iter.hasNext(); ) {
|
||||
String cur = (String)iter.next();
|
||||
if ("content-type".equalsIgnoreCase(cur)) {
|
||||
type = (String)params.get(cur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
post.addAttachment(filename.trim(), req.getInputStream("entryfile" + i), type);
|
||||
}
|
||||
}
|
||||
|
||||
post.renderPreview(out);
|
||||
out.write("<hr /><span class=\"b_postConfirm\"><form action=\"" + getPostURI() + "\" method=\"POST\">\n");
|
||||
writeAuthActionFields(out);
|
||||
out.write("Please confirm that the above is ok");
|
||||
if (BlogManager.instance().authorizeRemote(user)) {
|
||||
out.write(", and select what additional archives you want the post transmitted to. ");
|
||||
out.write("To make changes, hit your browser's back arrow and try again.\n");
|
||||
out.write("Remote archive to push this post to: ");
|
||||
out.write("<select class=\"b_postConfirm\" name=\"" + PARAM_REMOTE_ARCHIVE + "\">\n");
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if ("syndiearchive".equals(pn.getProtocol()))
|
||||
names.add(pn.getName());
|
||||
}
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
out.write("<option value=\"" + HTMLRenderer.sanitizeTagParam(name) + "\">"
|
||||
+ HTMLRenderer.sanitizeString(name) + "</option>\n");
|
||||
}
|
||||
out.write("<option name=\"\">None - don't push this post anywhere</option>\n");
|
||||
|
||||
out.write("</select><br />\n");
|
||||
out.write("If you don't push this post remotely now, you can do so later on the <a href=\"syndicate.jsp\">syndicate</a> screen ");
|
||||
out.write("by choosing an archive, verifying that they don't already have the post, and selecting which posts to push.\n");
|
||||
}
|
||||
out.write("</span><input class=\"b_postConfirm\" type=\"submit\" name=\"" + PARAM_ACTION
|
||||
+ "\" value=\"" + ACTION_CONFIRM + "\" />\n");
|
||||
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
|
||||
private void postEntry(User user, HttpServletRequest req, Archive archive, PostBean post, PrintWriter out) throws IOException {
|
||||
if (!authAction(req)) {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgErro\">Invalid form submission... stale data?</span></td></tr>");
|
||||
return;
|
||||
}
|
||||
String remArchive = req.getParameter(PARAM_REMOTE_ARCHIVE);
|
||||
post.setArchive(remArchive);
|
||||
BlogURI uri = post.postEntry();
|
||||
if (uri != null) {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgOk\">Entry <a class=\"b_postOkLink\" href=\"threads.jsp?regenerateIndex=true&post=" +
|
||||
uri.getKeyHash().toBase64() + "/" + uri.getEntryId() + "\">posted</a>!</span></td></tr>");
|
||||
} else {
|
||||
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgErro\">There was an unknown error posting the entry...</span></td></tr>");
|
||||
}
|
||||
}
|
||||
|
||||
private void displayNewForm(User user, HttpServletRequest req, PostBean post, PrintWriter out) throws IOException {
|
||||
// logged in and not confirmed because they didn't send us anything!
|
||||
// give 'em a new form
|
||||
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
|
||||
out.write("<form action=\"" + getPostURI() + "\" method=\"POST\" enctype=\"multipart/form-data\">\n");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\">\n");
|
||||
out.write("<span class=\"b_postField\">Post subject:</span> ");
|
||||
out.write("<input type=\"text\" class=\"b_postSubject\" size=\"80\" name=\"" + PARAM_SUBJECT
|
||||
+ "\" value=\"" + getParam(req,PARAM_SUBJECT) + "\" /><br />\n");
|
||||
out.write("<span class=\"b_postField\">Post tags:</span> ");
|
||||
out.write("<input type=\"text\" class=\"b_postTags\" size=\"20\" name=\"" + PARAM_TAGS
|
||||
+ "\" value=\"" + getParam(req, PARAM_TAGS) + "\" /><br />\n");
|
||||
out.write("<span class=\"b_postField\">Include public names?</span> ");
|
||||
out.write("<input class=\"b_postNames\" type=\"checkbox\" name=\"" + PARAM_INCLUDENAMES
|
||||
+ "\" value=\"true\" /><br />\n");
|
||||
out.write("<span class=\"b_postField\">Post content (in raw <a href=\"smlref.jsp\" target=\"_blank\">SML</a>, no headers):</span><br />\n");
|
||||
out.write("<textarea class=\"b_postText\" rows=\"6\" cols=\"80\" name=\"" + PARAM_TEXT + "\">" + getParam(req, PARAM_TEXT) + "</textarea><br />\n");
|
||||
out.write("<span class=\"b_postField\">SML post headers:</span><br />\n");
|
||||
out.write("<textarea class=\"b_postHeaders\" rows=\"3\" cols=\"80\" name=\"" + PARAM_HEADERS + "\">" + getParam(req, PARAM_HEADERS) + "</textarea><br />\n");
|
||||
|
||||
|
||||
String parentURI = req.getParameter(PARAM_PARENT);
|
||||
if ( (parentURI != null) && (parentURI.trim().length() > 0) )
|
||||
out.write("<input type=\"hidden\" name=\"" + PARAM_PARENT + "\" value=\"" + parentURI + "\" />\n");
|
||||
|
||||
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" />\n");
|
||||
|
||||
boolean inNewThread = getInNewThread(req);
|
||||
boolean refuseReplies = getRefuseReplies(req);
|
||||
|
||||
out.write(" in a new thread? <input type=\"checkbox\" value=\"true\" name=\"" + PARAM_IN_NEW_THREAD +
|
||||
(inNewThread ? "\" checked=\"true\" " : "\" " ) + " />\n");
|
||||
out.write(" refuse replies? <input type=\"checkbox\" value=\"true\" name=\"" + PARAM_REFUSE_REPLIES +
|
||||
(refuseReplies ? "\" checked=\"true\" " : "\" " ) + " />\n");
|
||||
|
||||
out.write(ATTACHMENT_FIELDS);
|
||||
|
||||
out.write("<hr />\n");
|
||||
out.write("<input class=\"b_postPreview\" type=\"submit\" name=\"Post\" value=\"Preview...\" /> ");
|
||||
out.write("<input class=\"b_postReset\" type=\"reset\" value=\"Cancel\" />\n");
|
||||
|
||||
if (parentURI != null) {
|
||||
out.write("<hr /><span id=\"parentText\" class=\"b_postParent\">");
|
||||
String decoded = DataHelper.getUTF8(Base64.decode(parentURI));
|
||||
post.renderReplyPreview(out, "entry://" + decoded);
|
||||
out.write("</span><hr/>\n");
|
||||
}
|
||||
|
||||
out.write("</td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
private boolean getInNewThread(HttpServletRequest req) {
|
||||
return getInNewThread(req.getParameter(PARAM_IN_NEW_THREAD));
|
||||
}
|
||||
private boolean getInNewThread(String val) {
|
||||
boolean rv = false;
|
||||
String inNewThread = val;
|
||||
if ( (inNewThread != null) && (Boolean.valueOf(inNewThread).booleanValue()) )
|
||||
rv = true;
|
||||
return rv;
|
||||
}
|
||||
private boolean getRefuseReplies(HttpServletRequest req) {
|
||||
return getRefuseReplies(req.getParameter(PARAM_REFUSE_REPLIES));
|
||||
}
|
||||
private boolean getRefuseReplies(String val) {
|
||||
boolean rv = false;
|
||||
String refuseReplies = val;
|
||||
if ( (refuseReplies != null) && (Boolean.valueOf(refuseReplies).booleanValue()) )
|
||||
rv = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private PostBean getPostBean(User user, HttpServletRequest req) {
|
||||
PostBean bean = (PostBean)req.getSession().getAttribute(ATTR_POST_BEAN);
|
||||
if (bean == null) {
|
||||
bean = new PostBean();
|
||||
req.getSession().setAttribute(ATTR_POST_BEAN, bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private String getParam(HttpServletRequest req, String param) {
|
||||
String val = req.getParameter(param);
|
||||
if (val == null) val = "";
|
||||
return val;
|
||||
}
|
||||
|
||||
private static final String ATTACHMENT_FIELDS = ""
|
||||
+ "<span class=\"b_postField\">Attachment 0:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile0\" /><br />"
|
||||
+ "<span class=\"b_postField\">Attachment 1:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile1\" /><br />"
|
||||
+ "<span class=\"b_postField\">Attachment 2:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile2\" /><br />"
|
||||
+ "<span class=\"b_postField\">Attachment 3:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile3\" /><br />\n";
|
||||
|
||||
protected String getTitle() { return "Syndie :: Post new content"; }
|
||||
}
|
||||
222
apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
Normal file
@@ -0,0 +1,222 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Render the requested profile
|
||||
*
|
||||
*/
|
||||
public class ProfileServlet extends BaseServlet {
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
Hash author = null;
|
||||
String str = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
|
||||
if (str != null) {
|
||||
try {
|
||||
author = new Hash();
|
||||
author.fromBase64(str);
|
||||
} catch (DataFormatException dfe) {
|
||||
author = null;
|
||||
}
|
||||
} else {
|
||||
author = user.getBlog();
|
||||
}
|
||||
|
||||
String uri = req.getRequestURI();
|
||||
|
||||
if (author == null) {
|
||||
renderInvalidProfile(out);
|
||||
} else if ( (user.getBlog() != null) && (user.getBlog().equals(author)) ) {
|
||||
renderMyProfile(user, uri, out, archive);
|
||||
} else {
|
||||
renderProfile(user, uri, out, author, archive);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderInvalidProfile(PrintWriter out) throws IOException {
|
||||
out.write(INVALID_PROFILE);
|
||||
}
|
||||
|
||||
private void renderMyProfile(User user, String baseURI, PrintWriter out, Archive archive) throws IOException {
|
||||
BlogInfo info = archive.getBlogInfo(user.getBlog());
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
out.write("<!-- " + info.toString() + "-->\n");
|
||||
out.write("<form action=\"" + baseURI + "\" method=\"POST\">\n");
|
||||
writeAuthActionFields(out);
|
||||
// now add the form to update
|
||||
out.write("<tr><td colspan=\"3\">Your profile</td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Name: <input type=\"text\" name=\""
|
||||
+ ThreadedHTMLRenderer.PARAM_PROFILE_NAME + "\" value=\""
|
||||
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.NAME)) + "\"></td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Account description: <input type=\"text\" name=\""
|
||||
+ ThreadedHTMLRenderer.PARAM_PROFILE_DESC + "\" value=\""
|
||||
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.DESCRIPTION)) + "\"></td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Contact information: <input type=\"text\" name=\""
|
||||
+ ThreadedHTMLRenderer.PARAM_PROFILE_URL + "\" value=\""
|
||||
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.CONTACT_URL)) + "\"></td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Other attributes:<br /><textarea rows=\"3\" name=\""
|
||||
+ ThreadedHTMLRenderer.PARAM_PROFILE_OTHER + "\" cols=\"60\">");
|
||||
String props[] = info.getProperties();
|
||||
if (props != null) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (!BlogInfo.NAME.equals(props[i]) &&
|
||||
!BlogInfo.DESCRIPTION.equals(props[i]) &&
|
||||
!BlogInfo.EDITION.equals(props[i]) &&
|
||||
!BlogInfo.OWNER_KEY.equals(props[i]) &&
|
||||
!BlogInfo.POSTERS.equals(props[i]) &&
|
||||
!BlogInfo.SIGNATURE.equals(props[i]) &&
|
||||
!BlogInfo.CONTACT_URL.equals(props[i])) {
|
||||
out.write(HTMLRenderer.sanitizeString(props[i], false) + ": "
|
||||
+ HTMLRenderer.sanitizeString(info.getProperty(props[i]), false) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write("</textarea></td></tr>\n");
|
||||
|
||||
if (user.getAuthenticated()) {
|
||||
if ( (user.getUsername() == null) || (user.getUsername().equals(BlogManager.instance().getDefaultLogin())) ) {
|
||||
// this is the default user, don't let them change the password
|
||||
} else {
|
||||
out.write("<tr><td colspan=\"3\">Old Password: <input type=\"password\" name=\"oldPassword\" /></td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n");
|
||||
out.write("<tr><td colspan=\"3\">Password again: <input type=\"password\" name=\"passwordConfirm\" /></td></tr>\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Update profile\" /></td></tr>\n");
|
||||
out.write("</form>\n");
|
||||
}
|
||||
|
||||
private void renderProfile(User user, String baseURI, PrintWriter out, Hash author, Archive archive) throws IOException {
|
||||
out.write("<tr><td colspan=\"3\">Profile for <a href=\"" + getControlTarget() + "?"
|
||||
+ ThreadedHTMLRenderer.PARAM_AUTHOR + '=' + author.toBase64()
|
||||
+ "\" title=\"View threads by the profiled author\">");
|
||||
PetName pn = user.getPetNameDB().getByLocation(author.toBase64());
|
||||
BlogInfo info = archive.getBlogInfo(author);
|
||||
if (pn != null) {
|
||||
out.write(pn.getName());
|
||||
String name = null;
|
||||
if (info != null)
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
|
||||
if ( (name == null) || (name.trim().length() <= 0) )
|
||||
name = author.toBase64().substring(0, 6);
|
||||
|
||||
out.write(" (" + name + ")");
|
||||
} else {
|
||||
String name = null;
|
||||
if (info != null)
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
|
||||
if ( (name == null) || (name.trim().length() <= 0) )
|
||||
name = author.toBase64().substring(0, 6);
|
||||
out.write(name);
|
||||
}
|
||||
out.write("</a>");
|
||||
if (info != null)
|
||||
out.write(" [edition " + info.getEdition() + "]");
|
||||
out.write("</td></tr>\n");
|
||||
|
||||
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
|
||||
if (pn == null) {
|
||||
out.write("<tr><td colspan=\"3\">Not currently bookmarked. Add them to your ");
|
||||
String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<a href=\"" + addFav + "\" title=\"Threads by favorite authors are shown specially\">favorites</a> or ");
|
||||
out.write("<a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">ignored</a> ");
|
||||
out.write("</td></tr>\n");
|
||||
} else if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) {
|
||||
out.write("<tr><td colspan=\"3\">Currently ignored - threads they create are hidden.</td></tr>\n");
|
||||
String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_IGNORE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + remIgnore + "\">Unignore " + pn.getName() + "</a></td></tr>\n");
|
||||
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
|
||||
} else if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) {
|
||||
out.write("<tr><td colspan=\"3\">Currently marked as a favorite author - threads they participate in " +
|
||||
"are highlighted.</td></tr>\n");
|
||||
String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_FAVORITE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + remIgnore + "\">Remove " + pn.getName() + " from the list of favorite authors</a></td></tr>\n");
|
||||
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">Ignore the author</a></td></tr>");
|
||||
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
|
||||
} else {
|
||||
out.write("<tr><td colspan=\"3\">Currently bookmarked. Add them to your ");
|
||||
String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<a href=\"" + addFav + "\" title=\"Threads by favorite authors are shown specially\">favorites</a> or ");
|
||||
out.write("<a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">ignored</a> list</td></tr>");
|
||||
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
|
||||
baseURI, "", "", "", "", "", author.toBase64());
|
||||
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
|
||||
}
|
||||
|
||||
if (info != null) {
|
||||
String descr = info.getProperty(BlogInfo.DESCRIPTION);
|
||||
if ( (descr != null) && (descr.trim().length() > 0) )
|
||||
out.write("<tr><td colspan=\"3\">Account description: " + HTMLRenderer.sanitizeString(descr) + "</td></tr>\n");
|
||||
|
||||
String contactURL = info.getProperty(BlogInfo.CONTACT_URL);
|
||||
if ( (contactURL != null) && (contactURL.trim().length() > 0) )
|
||||
out.write("<tr><td colspan=\"3\">Contact information: "
|
||||
+ HTMLRenderer.sanitizeString(contactURL) + "</td></tr>\n");
|
||||
|
||||
String props[] = info.getProperties();
|
||||
int altCount = 0;
|
||||
if (props != null)
|
||||
for (int i = 0; i < props.length; i++)
|
||||
if (!BlogInfo.NAME.equals(props[i]) &&
|
||||
!BlogInfo.DESCRIPTION.equals(props[i]) &&
|
||||
!BlogInfo.EDITION.equals(props[i]) &&
|
||||
!BlogInfo.OWNER_KEY.equals(props[i]) &&
|
||||
!BlogInfo.POSTERS.equals(props[i]) &&
|
||||
!BlogInfo.SIGNATURE.equals(props[i]) &&
|
||||
!BlogInfo.CONTACT_URL.equals(props[i]))
|
||||
altCount++;
|
||||
if (altCount > 0) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (!BlogInfo.NAME.equals(props[i]) &&
|
||||
!BlogInfo.DESCRIPTION.equals(props[i]) &&
|
||||
!BlogInfo.EDITION.equals(props[i]) &&
|
||||
!BlogInfo.OWNER_KEY.equals(props[i]) &&
|
||||
!BlogInfo.POSTERS.equals(props[i]) &&
|
||||
!BlogInfo.SIGNATURE.equals(props[i]) &&
|
||||
!BlogInfo.CONTACT_URL.equals(props[i])) {
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write(HTMLRenderer.sanitizeString(props[i]) + ": "
|
||||
+ HTMLRenderer.sanitizeString(info.getProperty(props[i])));
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTitle() { return "Syndie :: View profile"; }
|
||||
|
||||
private static final String INVALID_PROFILE = "<tr><td colspan=\"3\">The profile requested is invalid</td></tr>\n";
|
||||
}
|
||||
@@ -28,21 +28,46 @@ public class RSSServlet extends HttpServlet {
|
||||
if (user == null) {
|
||||
String login = req.getParameter("login");
|
||||
String pass = req.getParameter("password");
|
||||
user = new User();
|
||||
BlogManager.instance().login(user, login, pass); // ignore failures - user will just be unauthorized
|
||||
if (!user.getAuthenticated())
|
||||
user = BlogManager.instance().login(login, pass); // ignore failures - user will just be unauthorized
|
||||
if (!user.getAuthenticated()) {
|
||||
user.invalidate();
|
||||
user = BlogManager.instance().getDefaultUser();
|
||||
}
|
||||
}
|
||||
|
||||
String selector = req.getParameter("selector");
|
||||
if ( (selector == null) || (selector.length() <= 0) ) {
|
||||
selector = getDefaultSelector(user);
|
||||
String tags = req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS);
|
||||
Set tagSet = new HashSet();
|
||||
if (tags != null) {
|
||||
StringTokenizer tok = new StringTokenizer(tags, " \n\t\r");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String tag = (String)tok.nextToken();
|
||||
tag = tag.trim();
|
||||
if (tag.length() > 0)
|
||||
tagSet.add(tag);
|
||||
}
|
||||
}
|
||||
ArchiveViewerBean.Selector sel = new ArchiveViewerBean.Selector(selector);
|
||||
|
||||
int count = 10;
|
||||
String wanted = req.getParameter("wanted");
|
||||
if (wanted != null) {
|
||||
try {
|
||||
count = Integer.parseInt(wanted);
|
||||
} catch (NumberFormatException nfe) {
|
||||
count = 10;
|
||||
}
|
||||
}
|
||||
if (count < 0) count = 10;
|
||||
if (count > 100) count = 100;
|
||||
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
ArchiveIndex index = archive.getIndex();
|
||||
List entries = ArchiveViewerBean.pickEntryURIs(user, index, sel.blog, sel.tag, sel.entry, sel.group);
|
||||
FilteredThreadIndex index = new FilteredThreadIndex(user, archive, tagSet, null);
|
||||
List entries = new ArrayList();
|
||||
// depth first search of the most recent threads
|
||||
for (int i = 0; i < count && i < index.getRootCount(); i++) {
|
||||
ThreadNode node = index.getRoot(i);
|
||||
if (node != null)
|
||||
walkTree(entries, node);
|
||||
}
|
||||
|
||||
StringBuffer cur = new StringBuffer();
|
||||
cur.append(req.getScheme());
|
||||
@@ -58,22 +83,13 @@ public class RSSServlet extends HttpServlet {
|
||||
out.write("<rss version=\"2.0\">\n");
|
||||
out.write(" <channel>\n");
|
||||
out.write(" <title>Syndie feed</title>\n");
|
||||
out.write(" <link>" + urlPrefix + HTMLRenderer.sanitizeXML(HTMLRenderer.getPageURL(sel.blog, sel.tag, sel.entry, sel.group, 5, 0, false, false)) +"</link>\n");
|
||||
String page = urlPrefix;
|
||||
if (tags != null)
|
||||
page = page + "threads.jsp?" + ThreadedHTMLRenderer.PARAM_TAGS + '=' + HTMLRenderer.sanitizeXML(tags);
|
||||
out.write(" <link>" + page +"</link>\n");
|
||||
out.write(" <description>Summary of the latest Syndie posts</description>\n");
|
||||
out.write(" <generator>Syndie</generator>\n");
|
||||
|
||||
int count = 10;
|
||||
String wanted = req.getParameter("wanted");
|
||||
if (wanted != null) {
|
||||
try {
|
||||
count = Integer.parseInt(wanted);
|
||||
} catch (NumberFormatException nfe) {
|
||||
count = 10;
|
||||
}
|
||||
}
|
||||
if (count < 0) count = 10;
|
||||
if (count > 100) count = 100;
|
||||
|
||||
RSSRenderer r = new RSSRenderer(I2PAppContext.getGlobalContext());
|
||||
for (int i = 0; i < count && i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
@@ -86,10 +102,13 @@ public class RSSServlet extends HttpServlet {
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static String getDefaultSelector(User user) {
|
||||
if ( (user == null) || (user.getDefaultSelector() == null) )
|
||||
return BlogManager.instance().getArchive().getDefaultSelector();
|
||||
else
|
||||
return user.getDefaultSelector();
|
||||
private void walkTree(List uris, ThreadNode node) {
|
||||
if (node == null)
|
||||
return;
|
||||
if (uris.contains(node))
|
||||
return;
|
||||
uris.add(node.getEntry());
|
||||
for (int i = 0; i < node.getChildCount(); i++)
|
||||
walkTree(uris, node.getChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.i2p.util.EepPost;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -130,7 +131,7 @@ public class RemoteArchiveBean {
|
||||
|
||||
for (int i = 0; i < urls.size(); i++)
|
||||
_statusMessages.add("Scheduling blog post fetching for " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener());
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener(user));
|
||||
}
|
||||
|
||||
public void fetchSelectedBulk(User user, Map parameters) {
|
||||
@@ -184,9 +185,16 @@ public class RemoteArchiveBean {
|
||||
File tmp = File.createTempFile("fetchBulk", ".zip", BlogManager.instance().getTempDir());
|
||||
|
||||
boolean shouldProxy = (_proxyHost != null) && (_proxyPort > 0);
|
||||
EepGet get = new EepGet(_context, shouldProxy, _proxyHost, _proxyPort, 0, tmp.getAbsolutePath(), url.toString(), postData.toString());
|
||||
get.addStatusListener(new BulkFetchListener(tmp));
|
||||
get.fetch();
|
||||
final EepGet get = new EepGet(_context, shouldProxy, _proxyHost, _proxyPort, 0, tmp.getAbsolutePath(), url.toString(), postData.toString());
|
||||
get.addStatusListener(new BulkFetchListener(user, tmp));
|
||||
|
||||
if (shouldBlock) {
|
||||
get.fetch();
|
||||
} else {
|
||||
I2PThread t = new I2PThread(new Runnable() { public void run() { get.fetch(); } }, "Syndie fetcher");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + HTMLRenderer.sanitizeString(url.toString()) + ": " + ioe.getMessage());
|
||||
}
|
||||
@@ -210,7 +218,7 @@ public class RemoteArchiveBean {
|
||||
File t = File.createTempFile("fetchBulk", ".dat", BlogManager.instance().getTempDir());
|
||||
tmpFiles.add(t);
|
||||
}
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener(), shouldBlock);
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener(user), shouldBlock);
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch posts: " + HTMLRenderer.sanitizeString(urls.toString()));
|
||||
}
|
||||
@@ -258,7 +266,7 @@ public class RemoteArchiveBean {
|
||||
|
||||
for (int i = 0; i < urls.size(); i++)
|
||||
_statusMessages.add("Fetch all entries: " + HTMLRenderer.sanitizeString((String)urls.get(i)));
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener());
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener(user));
|
||||
}
|
||||
|
||||
private void fetch(List urls, List tmpFiles, User user, EepGet.StatusListener lsnr) {
|
||||
@@ -278,11 +286,11 @@ public class RemoteArchiveBean {
|
||||
_proxyHost = null;
|
||||
_proxyPort = -1;
|
||||
_exportCapable = false;
|
||||
if (user == null) user = new User();
|
||||
if (user == null) user = BlogManager.instance().getDefaultUser();
|
||||
|
||||
if ( (schema == null) || (schema.trim().length() <= 0) ||
|
||||
(location == null) || (location.trim().length() <= 0) ) {
|
||||
_statusMessages.add("Location must be specified");
|
||||
_statusMessages.add("Location must be specified [" + location + "] [" + schema + "]");
|
||||
_fetchIndexInProgress = false;
|
||||
return;
|
||||
}
|
||||
@@ -344,7 +352,7 @@ public class RemoteArchiveBean {
|
||||
_archiveFile = file;
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? " " + cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
@@ -382,7 +390,7 @@ public class RemoteArchiveBean {
|
||||
private class MetadataStatusListener implements EepGet.StatusListener {
|
||||
public MetadataStatusListener() {}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? " " + cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
@@ -420,9 +428,12 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
private class BlogStatusListener implements EepGet.StatusListener {
|
||||
public BlogStatusListener() {}
|
||||
private User _user;
|
||||
public BlogStatusListener(User user) {
|
||||
_user = user;
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? " " + cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
@@ -456,6 +467,7 @@ public class RemoteArchiveBean {
|
||||
} else {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " imported");
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
_user.dataImported();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -477,11 +489,13 @@ public class RemoteArchiveBean {
|
||||
*/
|
||||
private class BulkFetchListener implements EepGet.StatusListener {
|
||||
private File _tmp;
|
||||
public BulkFetchListener(File tmp) {
|
||||
private User _user;
|
||||
public BulkFetchListener(User user, File tmp) {
|
||||
_user = user;
|
||||
_tmp = tmp;
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? " " + cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
@@ -491,7 +505,7 @@ public class RemoteArchiveBean {
|
||||
ZipInputStream zi = null;
|
||||
try {
|
||||
zi = new ZipInputStream(new FileInputStream(file));
|
||||
|
||||
boolean postImported = false;
|
||||
while (true) {
|
||||
ZipEntry entry = zi.getNextEntry();
|
||||
if (entry == null)
|
||||
@@ -532,11 +546,14 @@ public class RemoteArchiveBean {
|
||||
continue;
|
||||
} else {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " imported");
|
||||
postImported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
if (postImported)
|
||||
_user.dataImported();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.debug("Error importing", ioe);
|
||||
@@ -637,9 +654,7 @@ public class RemoteArchiveBean {
|
||||
buf.append("<tr class=\"b_remBlog\"><td class=\"b_remBlog\" colspan=\"5\" align=\"left\" valign=\"top\">\n");
|
||||
BlogInfo info = archive.getBlogInfo(blog);
|
||||
if (info != null) {
|
||||
buf.append("<a class=\"b_remBlog\" href=\"");
|
||||
buf.append(HTMLRenderer.getPageURL(blog, null, -1, -1, -1, user.getShowExpanded(), user.getShowImages()));
|
||||
buf.append("\">").append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME))).append("</a>: ");
|
||||
buf.append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME))).append(": ");
|
||||
buf.append("<span class=\"b_remBlogDesc\">").append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.DESCRIPTION)));
|
||||
buf.append("</span>\n");
|
||||
} else {
|
||||
@@ -661,8 +676,7 @@ public class RemoteArchiveBean {
|
||||
newEntries++;
|
||||
shownEntries++;
|
||||
} else {
|
||||
String page = HTMLRenderer.getPageURL(blog, null, uri.getEntryId(), -1, -1,
|
||||
user.getShowExpanded(), user.getShowImages());
|
||||
String page = "threads.jsp?" + ThreadedHTMLRenderer.PARAM_VIEW_POST + '=' + blog.toBase64() + '/' + uri.getEntryId();
|
||||
buf.append("<td class=\"b_remDetail\"><a class=\"b_remLocal\" href=\"" + page + "\">(local)</a></td>\n");
|
||||
}
|
||||
buf.append("<td class=\"b_remDetail\"><span class=\"b_remDate\">" + getDate(uri.getEntryId()) + "</span></td>\n");
|
||||
@@ -671,7 +685,8 @@ public class RemoteArchiveBean {
|
||||
buf.append("<td class=\"b_remDetail\">");
|
||||
for (Iterator titer = new TreeSet(_remoteIndex.getBlogEntryTags(uri)).iterator(); titer.hasNext(); ) {
|
||||
String tag = (String)titer.next();
|
||||
buf.append("<a class=\"b_remTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
String page = "threads.jsp?" + ThreadedHTMLRenderer.PARAM_TAGS + '=' + HTMLRenderer.sanitizeTagParam(tag);
|
||||
buf.append("<a class=\"b_remTag\" href=\"" + page + "\">" + HTMLRenderer.sanitizeString(tag) + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
@@ -700,7 +715,8 @@ public class RemoteArchiveBean {
|
||||
buf.append("<td class=\"b_remLocalTags\">");
|
||||
for (Iterator titer = new TreeSet(localIndex.getBlogEntryTags(uri)).iterator(); titer.hasNext(); ) {
|
||||
String tag = (String)titer.next();
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
String page = "threads.jsp?" + ThreadedHTMLRenderer.PARAM_TAGS + '=' + HTMLRenderer.sanitizeTagParam(tag);
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + page + "\">" + HTMLRenderer.sanitizeString(tag) + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
@@ -737,7 +753,8 @@ public class RemoteArchiveBean {
|
||||
buf.append("<td class=\"b_remLocalTags\">");
|
||||
for (Iterator titer = new TreeSet(localIndex.getBlogEntryTags(uri)).iterator(); titer.hasNext(); ) {
|
||||
String tag = (String)titer.next();
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
String page = "threads.jsp?" + ThreadedHTMLRenderer.PARAM_TAGS + '=' + HTMLRenderer.sanitizeTagParam(tag);
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + page + "\">" + HTMLRenderer.sanitizeString(tag) + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
|
||||
49
apps/syndie/java/src/net/i2p/syndie/web/SwitchServlet.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Login/register form
|
||||
*
|
||||
*/
|
||||
public class SwitchServlet extends BaseServlet {
|
||||
protected String getTitle() { return "Syndie :: Login/Register"; }
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
out.write("<form action=\"" + getControlTarget() + "\" method=\"POST\">\n");
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\"><b>Log in to an existing account</b></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Login\" />\n" +
|
||||
"<input type=\"submit\" name=\"action\" value=\"Cancel\" />\n" +
|
||||
"<input type=\"submit\" name=\"action\" value=\"Logout\" /></td></tr>\n" +
|
||||
"</form>\n" +
|
||||
"<tr><td colspan=\"3\"><hr /></td></tr>\n" +
|
||||
"<form action=\"" + ThreadedHTMLRenderer.buildProfileURL(null) + "\" method=\"POST\">\n" +
|
||||
"<tr><td colspan=\"3\"><b>Register a new account</b></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /> (only known locally)</td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Public name: <input type=\"text\" name=\"accountName\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Description: <input type=\"text\" name=\"description\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Contact URL: <input type=\"text\" name=\"contactURL\" /></td></tr>\n" +
|
||||
"<tr><td colspan=\"3\">Registration password: <input type=\"password\" name=\"registrationPass\" />" +
|
||||
" (only necessary if the Syndie administrator requires it)</td></tr>\n" +
|
||||
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Register\" /></td></tr>\n" +
|
||||
"</form>\n");
|
||||
}
|
||||
}
|
||||
153
apps/syndie/java/src/net/i2p/syndie/web/SyndicateServlet.java
Normal file
@@ -0,0 +1,153 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Syndicate with another remote Syndie node
|
||||
*
|
||||
*/
|
||||
public class SyndicateServlet extends BaseServlet {
|
||||
protected String getTitle() { return "Syndie :: Syndicate"; }
|
||||
|
||||
public static final String PARAM_SCHEMA = "schema";
|
||||
public static final String PARAM_LOCATION = "location";
|
||||
public static final String PARAM_PETNAME = "petname";
|
||||
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
if (!BlogManager.instance().authorizeRemote(user)) {
|
||||
out.write("<tr><td colspan=\"3\">Sorry, you are not authorized to access remote archives</td></tr>\n");
|
||||
} else {
|
||||
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">");
|
||||
displayForm(user, req, out);
|
||||
handleRequest(user, req, index, out);
|
||||
out.write("</form>\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRequest(User user, HttpServletRequest req, ThreadIndex index, PrintWriter out) throws IOException {
|
||||
RemoteArchiveBean remote = getRemote(req);
|
||||
String action = req.getParameter("action");
|
||||
if ("Continue...".equals(action)) {
|
||||
String location = req.getParameter(PARAM_LOCATION);
|
||||
String pn = req.getParameter(PARAM_PETNAME);
|
||||
if ( (pn != null) && (pn.trim().length() > 0) ) {
|
||||
PetName pnval = user.getPetNameDB().getByName(pn);
|
||||
if (pnval != null) location = pnval.getLocation();
|
||||
}
|
||||
|
||||
remote.fetchIndex(user, req.getParameter(PARAM_SCHEMA), location,
|
||||
req.getParameter("proxyhost"),
|
||||
req.getParameter("proxyport"));
|
||||
} else if ("Fetch metadata".equals(action)) {
|
||||
remote.fetchMetadata(user, req.getParameterMap());
|
||||
} else if ("Fetch selected entries".equals(action)) {
|
||||
//remote.fetchSelectedEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, req.getParameterMap());
|
||||
} else if ("Fetch all new entries".equals(action)) {
|
||||
//remote.fetchAllEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, req.getParameterMap());
|
||||
} else if ("Post selected entries".equals(action)) {
|
||||
remote.postSelectedEntries(user, req.getParameterMap());
|
||||
}
|
||||
String msgs = remote.getStatus();
|
||||
if ( (msgs != null) && (msgs.length() > 0) ) {
|
||||
out.write("<pre class=\"b_remoteProgress\">");
|
||||
out.write(msgs);
|
||||
out.write("<a class=\"b_remoteProgress\" href=\"");
|
||||
out.write(req.getRequestURI());
|
||||
out.write("\">Refresh</a></pre><br />\n");
|
||||
}
|
||||
|
||||
if (remote.getFetchIndexInProgress()) {
|
||||
out.write("<span class=\"b_remoteProgress\">Please wait while the index is being fetched ");
|
||||
out.write("from ");
|
||||
out.write(remote.getRemoteLocation());
|
||||
out.write(".</span>");
|
||||
} else if (remote.getRemoteIndex() != null) {
|
||||
// remote index is NOT null!
|
||||
out.write("<span class=\"b_remoteLocation\">");
|
||||
out.write(remote.getRemoteLocation());
|
||||
out.write("</span>");
|
||||
out.write("<a class=\"b_remoteRefetch\" href=\"");
|
||||
out.write(req.getRequestURI());
|
||||
out.write("?" + PARAM_SCHEMA + "=" + remote.getRemoteSchema() + "&" + PARAM_LOCATION + "=" + remote.getRemoteLocation());
|
||||
if (remote.getProxyHost() != null && remote.getProxyPort() > 0) {
|
||||
out.write("&proxyhost=" + remote.getProxyHost() + "&proxyport=" + remote.getProxyPort());
|
||||
}
|
||||
out.write("&action=Continue...\">(refetch)</a>:<br />\n");
|
||||
|
||||
remote.renderDeltaForm(user, BlogManager.instance().getArchive().getIndex(), out);
|
||||
out.write("<textarea class=\"b_remoteIndex\" rows=\"5\" cols=\"120\">" +
|
||||
remote.getRemoteIndex().toString() + "</textarea>");
|
||||
}
|
||||
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
|
||||
private void displayForm(User user, HttpServletRequest req, PrintWriter out) throws IOException {
|
||||
writeAuthActionFields(out);
|
||||
out.write("<tr><td colspan=\"3\">");
|
||||
out.write("<span class=\"b_remoteChooser\"><span class=\"b_remoteChooserField\">Import from:</span>\n");
|
||||
out.write("<select class=\"b_remoteChooserNet\" name=\"" + PARAM_SCHEMA + "\">\n");
|
||||
String schema = req.getParameter(PARAM_SCHEMA);
|
||||
out.write("<option value=\"web\" ");
|
||||
if ("web".equals(schema))
|
||||
out.write("selected=\"true\" ");
|
||||
out.write(">I2P/Web/Tor/Freenet</option>\n");
|
||||
|
||||
out.write("</select>\n");
|
||||
out.write("<span class=\"b_remoteChooserField\">Proxy</span>\n");
|
||||
out.write("<input class=\"b_remoteChooserHost\" type=\"text\" size=\"10\" name=\"proxyhost\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultProxyHost());
|
||||
out.write("\" />\n");
|
||||
out.write("<input class=\"b_remoteChooserPort\" type=\"text\" size=\"4\" name=\"proxyport\" value=\"");
|
||||
out.write(BlogManager.instance().getDefaultProxyPort());
|
||||
out.write("\" /><br />\n");
|
||||
out.write("<span class=\"b_remoteChooserField\">Bookmarked archives:</span>\n");
|
||||
out.write("<select class=\"b_remoteChooserPN\" name=\"" + PARAM_PETNAME + "\">");
|
||||
out.write("<option value=\"\">Custom location</option>");
|
||||
|
||||
for (Iterator iter = user.getPetNameDB().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = (PetName)iter.next();
|
||||
if (AddressesServlet.PROTO_ARCHIVE.equals(pn.getProtocol())) {
|
||||
out.write("<option value=\"");
|
||||
out.write(HTMLRenderer.sanitizeTagParam(pn.getName()));
|
||||
out.write("\">");
|
||||
out.write(HTMLRenderer.sanitizeString(pn.getName()));
|
||||
out.write("</option>");
|
||||
}
|
||||
}
|
||||
out.write("</select> or ");
|
||||
out.write("<input type=\"text\" class=\"b_remoteChooserLocation\" name=\"" + PARAM_LOCATION + "\" size=\"30\" value=\"");
|
||||
String reqLoc = req.getParameter("location");
|
||||
if (reqLoc != null)
|
||||
out.write(reqLoc);
|
||||
out.write("\" />\n");
|
||||
out.write("<input class=\"b_remoteChooserContinue\" type=\"submit\" name=\"action\" value=\"Continue...\" /><br />\n");
|
||||
out.write("</span>\n");
|
||||
}
|
||||
|
||||
private static final String ATTR_REMOTE = "remote";
|
||||
protected RemoteArchiveBean getRemote(HttpServletRequest req) {
|
||||
RemoteArchiveBean remote = (RemoteArchiveBean)req.getSession().getAttribute(ATTR_REMOTE);
|
||||
if (remote == null) {
|
||||
remote = new RemoteArchiveBean();
|
||||
req.getSession().setAttribute(ATTR_REMOTE, remote);
|
||||
}
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
306
apps/syndie/java/src/net/i2p/syndie/web/ViewThreadedServlet.java
Normal file
@@ -0,0 +1,306 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Render the appropriate posts and the thread tree
|
||||
*
|
||||
*/
|
||||
public class ViewThreadedServlet extends BaseServlet {
|
||||
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
|
||||
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
|
||||
renderBody(user, req, out, index);
|
||||
|
||||
renderThreadNav(user, req, out, threadOffset, index);
|
||||
renderThreadTree(user, req, out, threadOffset, visibleEntry, archive, index);
|
||||
renderThreadNav(user, req, out, threadOffset, index);
|
||||
}
|
||||
|
||||
private void renderBody(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws IOException {
|
||||
ThreadedHTMLRenderer renderer = new ThreadedHTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
List posts = getPosts(archive, req, index);
|
||||
|
||||
String uri = req.getRequestURI();
|
||||
String off = req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET);
|
||||
String tags = req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS);
|
||||
String author = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
|
||||
|
||||
for (int i = 0; i < posts.size(); i++) {
|
||||
BlogURI post = (BlogURI)posts.get(i);
|
||||
renderer.render(user, out, archive, post, posts.size() == 1, index, uri, getAuthActionFields(), off, tags, author);
|
||||
}
|
||||
}
|
||||
|
||||
private List getPosts(Archive archive, HttpServletRequest req, ThreadIndex index) {
|
||||
List rv = new ArrayList(1);
|
||||
String post = req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST);
|
||||
BlogURI uri = getAsBlogURI(post);
|
||||
if ( (uri != null) && (uri.getEntryId() > 0) ) {
|
||||
rv.add(uri);
|
||||
} else {
|
||||
String thread = req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD);
|
||||
uri = getAsBlogURI(thread);
|
||||
if ( (uri != null) && (uri.getEntryId() > 0) ) {
|
||||
ThreadNode node = index.getNode(uri);
|
||||
if (node != null) {
|
||||
while (node.getParent() != null)
|
||||
node = node.getParent(); // hope the structure is loopless...
|
||||
// depth first traversal
|
||||
walkTree(rv, node);
|
||||
} else {
|
||||
rv.add(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void walkTree(List uris, ThreadNode node) {
|
||||
if (node == null)
|
||||
return;
|
||||
if (uris.contains(node))
|
||||
return;
|
||||
uris.add(node.getEntry());
|
||||
for (int i = 0; i < node.getChildCount(); i++)
|
||||
walkTree(uris, node.getChild(i));
|
||||
}
|
||||
private void renderThreadNav(User user, HttpServletRequest req, PrintWriter out, int threadOffset, ThreadIndex index) throws IOException {
|
||||
out.write("<tr class=\"threadNav\" id=\"threads\"><td colspan=\"2\" nowrap=\"true\">\n");
|
||||
out.write("<!-- thread nav begin -->\n");
|
||||
if (threadOffset == 0) {
|
||||
out.write("<< First Page ");
|
||||
} else {
|
||||
out.write("<a href=\"");
|
||||
out.write(getNavLink(req, 0));
|
||||
out.write("\"><< First Page</a> ");
|
||||
}
|
||||
if (threadOffset > 0) {
|
||||
out.write("<a href=\"");
|
||||
int nxt = threadOffset - 10;
|
||||
if (nxt < 0)
|
||||
nxt = 0;
|
||||
out.write(getNavLink(req, nxt));
|
||||
out.write("\">< Prev Page</a>\n");
|
||||
} else {
|
||||
out.write("< Prev Page\n");
|
||||
}
|
||||
out.write("</td><td class=\"threadNavRight\" nowrap=\"true\">\n");
|
||||
|
||||
int max = index.getRootCount();
|
||||
if (threadOffset + 10 > max) {
|
||||
out.write("Next Page> Last Page>>\n");
|
||||
} else {
|
||||
out.write("<a href=\"");
|
||||
out.write(getNavLink(req, threadOffset + 10));
|
||||
out.write("\">Next Page></a> <a href=\"");
|
||||
out.write(getNavLink(req, -1));
|
||||
out.write("\">Last Page>></a>\n");
|
||||
}
|
||||
out.write("<!-- thread nav end -->\n");
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
|
||||
private void renderThreadTree(User user, HttpServletRequest req, PrintWriter out, int threadOffset, BlogURI visibleEntry, Archive archive, ThreadIndex index) throws IOException {
|
||||
int numThreads = 10;
|
||||
renderThreadTree(user, out, index, archive, req, threadOffset, numThreads, visibleEntry);
|
||||
}
|
||||
|
||||
private void renderThreadTree(User user, PrintWriter out, ThreadIndex index, Archive archive, HttpServletRequest req,
|
||||
int threadOffset, int numThreads, BlogURI visibleEntry) {
|
||||
|
||||
if ( (visibleEntry != null) && (empty(req, ThreadedHTMLRenderer.PARAM_OFFSET)) ) {
|
||||
// we want to jump to a specific thread in the nav
|
||||
threadOffset = index.getRoot(visibleEntry);
|
||||
}
|
||||
|
||||
if (threadOffset < 0)
|
||||
threadOffset = 0;
|
||||
out.write("<!-- threads begin -->\n");
|
||||
if (threadOffset + numThreads > index.getRootCount())
|
||||
numThreads = index.getRootCount() - threadOffset;
|
||||
TreeRenderState state = new TreeRenderState(new ArrayList());
|
||||
|
||||
int written = 0;
|
||||
for (int curRoot = threadOffset; curRoot < numThreads + threadOffset; curRoot++) {
|
||||
ThreadNode node = index.getRoot(curRoot);
|
||||
out.write("<!-- thread begin curRoot=" + curRoot + " threadOffset=" + threadOffset + " -->\n");
|
||||
renderThread(user, out, index, archive, req, node, 0, visibleEntry, state);
|
||||
out.write("<!-- thread end -->\n");
|
||||
written++;
|
||||
}
|
||||
|
||||
if (written <= 0)
|
||||
out.write("<tr class=\"threadEven\"><td colspan=\"3\">No matching threads</td></tr>\n");
|
||||
|
||||
out.write("<!-- threads end -->\n");
|
||||
}
|
||||
|
||||
private boolean renderThread(User user, PrintWriter out, ThreadIndex index, Archive archive, HttpServletRequest req,
|
||||
ThreadNode node, int depth, BlogURI visibleEntry, TreeRenderState state) {
|
||||
boolean isFavorite = false;
|
||||
boolean ignored = false;
|
||||
|
||||
HTMLRenderer rend = new HTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
SMLParser parser = new SMLParser(I2PAppContext.getGlobalContext());
|
||||
|
||||
PetName pn = user.getPetNameDB().getByLocation(node.getEntry().getKeyHash().toBase64());
|
||||
if (pn != null) {
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) {
|
||||
isFavorite = true;
|
||||
}
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE))
|
||||
ignored = true;
|
||||
}
|
||||
|
||||
state.incrementRowsWritten();
|
||||
if (state.getRowsWritten() % 2 == 0)
|
||||
out.write("<tr class=\"threadEven\">\n");
|
||||
else
|
||||
out.write("<tr class=\"threadOdd\">\n");
|
||||
|
||||
out.write("<td class=\"threadFlag\">");
|
||||
out.write(getFlagHTML(user, node));
|
||||
out.write("</td>\n<td class=\"threadLeft\">\n");
|
||||
for (int i = 0; i < depth; i++)
|
||||
out.write("<img src=\"images/threadIndent.png\" alt=\"\" border=\"0\" />");
|
||||
|
||||
boolean showChildren = false;
|
||||
|
||||
int childCount = node.getChildCount();
|
||||
|
||||
if (childCount > 0) {
|
||||
boolean allowCollapse = false;
|
||||
|
||||
if (visibleEntry != null) {
|
||||
if (node.getEntry().equals(visibleEntry)) {
|
||||
// noop
|
||||
} else if (node.containsEntry(visibleEntry)) {
|
||||
showChildren = true;
|
||||
allowCollapse = true;
|
||||
}
|
||||
} else {
|
||||
// noop
|
||||
}
|
||||
|
||||
if (allowCollapse) {
|
||||
out.write("<a href=\"");
|
||||
out.write(getCollapseLink(req, node));
|
||||
out.write("\" title=\"collapse thread\"><img border=\"0\" src=\"images/collapse.png\" alt=\"collapse\" /></a>\n");
|
||||
} else {
|
||||
out.write("<a href=\"");
|
||||
out.write(getExpandLink(req, node));
|
||||
out.write("\" title=\"expand thread\"><img border=\"0\" src=\"images/expand.png\" alt=\"expand\" /></a>\n");
|
||||
}
|
||||
} else {
|
||||
out.write("<img src=\"images/noSubthread.png\" alt=\"\" border=\"0\" />\n");
|
||||
}
|
||||
|
||||
out.write("<a href=\"");
|
||||
out.write(getProfileLink(req, node.getEntry().getKeyHash()));
|
||||
out.write("\" title=\"View the user's profile\">");
|
||||
|
||||
if (pn == null) {
|
||||
BlogInfo info = archive.getBlogInfo(node.getEntry().getKeyHash());
|
||||
String name = null;
|
||||
if (info != null)
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
if ( (name == null) || (name.trim().length() <= 0) )
|
||||
name = node.getEntry().getKeyHash().toBase64().substring(0,6);
|
||||
out.write(trim(name, 30));
|
||||
} else {
|
||||
out.write(trim(pn.getName(), 30));
|
||||
}
|
||||
out.write("</a>\n");
|
||||
|
||||
if ( (user.getBlog() != null) && (node.getEntry().getKeyHash().equals(user.getBlog())) ) {
|
||||
out.write("<img src=\"images/self.png\" alt=\"You wrote this\" border=\"0\" />\n");
|
||||
} else if (isFavorite) {
|
||||
out.write("<img src=\"images/favorites.png\" alt=\"favorites\" border=\"0\" />\n");
|
||||
} else if (ignored) {
|
||||
out.write("<img src=\"images/addToIgnored.png\" alt=\"ignored\" border=\"0\" />\n");
|
||||
} else {
|
||||
if (user.getAuthenticated()) {
|
||||
// give them a link to bookmark or ignore the peer
|
||||
out.write("(<a href=\"");
|
||||
out.write(getAddToGroupLink(req, node.getEntry().getKeyHash(), user, FilteredThreadIndex.GROUP_FAVORITE));
|
||||
out.write("\" title=\"Add as a friend\"><img src=\"images/addToFavorites.png\" alt=\"friend\" border=\"0\" /></a>\n");
|
||||
out.write("/<a href=\"");
|
||||
out.write(getAddToGroupLink(req, node.getEntry().getKeyHash(), user, FilteredThreadIndex.GROUP_IGNORE));
|
||||
out.write("\" title=\"Add to killfile\"><img src=\"images/addToIgnored.png\" alt=\"ignore\" border=\"0\" /></a>)\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.write(" @ ");
|
||||
out.write("<a href=\"");
|
||||
out.write(getViewPostLink(req, node, user, false));
|
||||
out.write("\" title=\"View post\">");
|
||||
out.write(rend.getEntryDate(node.getEntry().getEntryId()));
|
||||
out.write(": ");
|
||||
EntryContainer entry = archive.getEntry(node.getEntry());
|
||||
|
||||
HeaderReceiver rec = new HeaderReceiver();
|
||||
parser.parse(entry.getEntry().getText(), rec);
|
||||
String subject = rec.getHeader(HTMLRenderer.HEADER_SUBJECT);
|
||||
if (subject == null)
|
||||
subject = "";
|
||||
out.write(trim(subject, 40));
|
||||
out.write("</a>\n</td><td class=\"threadRight\">\n");
|
||||
out.write("<a href=\"");
|
||||
out.write(getViewThreadLink(req, node, user));
|
||||
out.write("\" title=\"View all posts in the thread\">view thread</a>\n");
|
||||
out.write("</td></tr>\n");
|
||||
|
||||
boolean rendered = true;
|
||||
|
||||
if (showChildren) {
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
ThreadNode child = node.getChild(i);
|
||||
boolean childRendered = renderThread(user, out, index, archive, req, child, depth+1, visibleEntry, state);
|
||||
rendered = rendered || childRendered;
|
||||
}
|
||||
}
|
||||
|
||||
return rendered;
|
||||
}
|
||||
|
||||
private String getFlagHTML(User user, ThreadNode node) {
|
||||
if ( (user.getBlog() != null) && (node.containsAuthor(user.getBlog())) )
|
||||
return "<img src=\"images/self.png\" border=\"0\" alt=\"You have posted in the thread\" />";
|
||||
|
||||
// grab all of the peers in the user's favorites group and check to see if
|
||||
// they posted something in the given thread, flagging it if they have
|
||||
boolean favoriteFound = false;
|
||||
for (Iterator iter = user.getPetNameDB().getNames().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = user.getPetNameDB().getByName((String)iter.next());
|
||||
if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) {
|
||||
Hash cur = new Hash();
|
||||
try {
|
||||
cur.fromBase64(pn.getLocation());
|
||||
if (node.containsAuthor(cur)) {
|
||||
favoriteFound = true;
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
if (favoriteFound)
|
||||
return "<img src=\"images/favorites.png\" border=\"0\" alt=\"flagged author posted in the thread\" />";
|
||||
else
|
||||
return " ";
|
||||
}
|
||||
|
||||
protected String getTitle() { return "Syndie :: View threads"; }
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
<span class="b_topnavHome"><a href="index.jsp" class="b_topnavHome">Home</a></span>
|
||||
<a href="admin.jsp" class="b_topnavAdmin">Syndie admin</a>
|
||||
<a href="remote.jsp" class="b_topnavRemote">Remote archives</a>
|
||||
<a href="rssimport.jsp" class="b_topnavRSSImport">RSS imports</a>
|
||||
<a href="import.jsp" class="b_topnavImport">Import</a>
|
||||
</td><td nowrap="nowrap" height="10" class="b_topnavUser"><%
|
||||
if ("true".equals(request.getParameter("logout"))) {
|
||||
@@ -25,9 +26,9 @@ if ( (login != null) && (pass != null) && (loginSubmit != null) && (loginSubmit.
|
||||
%>
|
||||
<% if (user.getAuthenticated()) { %>
|
||||
<span class="b_topnavUsername">Logged in as:</span> <em class="b_topnavUsername"><jsp:getProperty property="username" name="user" />:</em>
|
||||
<a class="b_topnavBlog" href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())%>"><%=HTMLRenderer.sanitizeString(ArchiveViewerBean.getBlogName(user.getBlogStr()))%></a>
|
||||
<a class="b_topnavPost" href="<%=HTMLRenderer.getPostURL(user.getBlog())%>">Post</a>
|
||||
<a class="b_topnavMeta" href="<%=HTMLRenderer.getMetadataURL(user.getBlog())%>">Metadata</a>
|
||||
<a class="b_topnavBlog" href="<%=""/*HTMLRenderer.getPageURL(user.getBlog(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())*/%>"><%=HTMLRenderer.sanitizeString(ArchiveViewerBean.getBlogName(user.getBlogStr()))%></a>
|
||||
<a class="b_topnavPost" href="<%=""/*HTMLRenderer.getPostURL(user.getBlog())*/%>">Post</a>
|
||||
<a class="b_topnavMeta" href="<%=""/*HTMLRenderer.getMetadataURL(user.getBlog())*/%>">Metadata</a>
|
||||
<a class="b_topnavAddr" href="addresses.jsp">Addressbook</a>
|
||||
<a class="b_topnavLogout" href="index.jsp?logout=true">Logout</a>
|
||||
<%} else {%>
|
||||
|
||||
23
apps/syndie/jsp/about.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html
|
||||
><head><title>What is Syndie?</title></head
|
||||
><body bgcolor="#BBBBFF">
|
||||
|
||||
<p>Perhaps the best introduction to Syndie can be found <a
|
||||
href="threads.jsp?post=ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1132012800001">in
|
||||
Syndie itself</a>.</p>
|
||||
|
||||
<p>Updates can be found by filtering for the <a
|
||||
href="threads.jsp?tags=syndie.intro">syndie.intro</a> tag (if you only want to
|
||||
receive posts that <a
|
||||
href="threads.jsp?author=ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=">jrandom</a>
|
||||
made with that tag, that can be <a
|
||||
href="threads.jsp?tags=syndie.intro&author=ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=">achieved</a>
|
||||
as well).</p>
|
||||
|
||||
<p>If you have any questions or problems with Syndie, just post them and
|
||||
syndicate it up to <a href="http://syndiemedia.i2p/">syndiemedia.i2p</a> (which should show up as the default archive
|
||||
on new installs). You can also use the <a href="http://forum.i2p.net/">I2P
|
||||
forums</a> if you're having trouble getting Syndie to work, and people are
|
||||
almost always around on the <a href="http://forum.i2p.net/viewtopic.php?t=952">#i2p irc
|
||||
channel</a>.</p>
|
||||
</body></html>
|
||||
@@ -1,227 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.data.*, net.i2p.syndie.*, net.i2p.client.naming.PetName, net.i2p.client.naming.PetNameDB, org.mortbay.servlet.MultiPartRequest, java.util.*, java.io.*" %><%
|
||||
request.setCharacterEncoding("UTF-8"); %><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia addressbook</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body><!-- auth? <%=user.getAuthenticated()%> remote? <%=user.getAllowAccessRemote()%> sched? <%=request.getParameter("scheduleSyndication")%> -->
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
if (!user.getAuthenticated()) {
|
||||
%><span class="b_addrMsgErr">You must log in to view your addressbook</span><%
|
||||
} else {
|
||||
PetNameDB names = user.getPetNameDB();
|
||||
String action = request.getParameter("action");
|
||||
if ( (action != null) && ("Change".equals(action)) ) {
|
||||
String oldPetname = request.getParameter("petname");
|
||||
PetName cur = names.getByName(oldPetname);
|
||||
if (cur != null) {
|
||||
cur.setName(request.getParameter("name"));
|
||||
cur.setNetwork(request.getParameter("network"));
|
||||
cur.setProtocol(request.getParameter("protocol"));
|
||||
cur.setIsPublic(null != request.getParameter("isPublic"));
|
||||
cur.setLocation(request.getParameter("location"));
|
||||
cur.setGroups(request.getParameter("groups"));
|
||||
names.removeName(oldPetname);
|
||||
names.add(cur);
|
||||
names.store(user.getAddressbookLocation());
|
||||
if ( ("syndiearchive".equals(cur.getProtocol())) && (BlogManager.instance().authorizeRemote(user)) ) {
|
||||
if (null != request.getParameter("scheduleSyndication")) {
|
||||
BlogManager.instance().scheduleSyndication(cur.getLocation());
|
||||
BlogManager.instance().writeConfig();
|
||||
} else {
|
||||
BlogManager.instance().unscheduleSyndication(cur.getLocation());
|
||||
BlogManager.instance().writeConfig();
|
||||
}
|
||||
}
|
||||
%><span class="b_addrMsgOk">Address updated</span><%
|
||||
}
|
||||
} else if ( (action != null) && ("Add".equals(action)) ) {
|
||||
PetName cur = names.getByName(request.getParameter("name"));
|
||||
if (cur != null) { %><span class="b_addrMsgErr">Address already exists</span><% } else {
|
||||
cur = new PetName();
|
||||
cur.setName(request.getParameter("name"));
|
||||
cur.setNetwork(request.getParameter("network"));
|
||||
cur.setProtocol(request.getParameter("protocol"));
|
||||
cur.setIsPublic(null != request.getParameter("isPublic"));
|
||||
cur.setLocation(request.getParameter("location"));
|
||||
cur.setGroups(request.getParameter("groups"));
|
||||
names.add(cur);
|
||||
names.store(user.getAddressbookLocation());
|
||||
if ( ("syndiearchive".equals(cur.getProtocol())) && (BlogManager.instance().authorizeRemote(user)) ) {
|
||||
if (null != request.getParameter("scheduleSyndication")) {
|
||||
BlogManager.instance().scheduleSyndication(cur.getLocation());
|
||||
BlogManager.instance().writeConfig();
|
||||
}
|
||||
}
|
||||
%><span class="b_addrMsgOk">Address added</span><%
|
||||
}
|
||||
} else if ( (action != null) && ("Delete".equals(action)) ) {
|
||||
PetName cur = names.getByName(request.getParameter("name"));
|
||||
if (cur != null) {
|
||||
if ( ("syndiearchive".equals(cur.getProtocol())) && (BlogManager.instance().authorizeRemote(user)) ) {
|
||||
BlogManager.instance().unscheduleSyndication(cur.getLocation());
|
||||
BlogManager.instance().writeConfig();
|
||||
}
|
||||
names.removeName(cur.getName());
|
||||
names.store(user.getAddressbookLocation());
|
||||
%><span class="b_addrMsgOk">Address removed</span><%
|
||||
}
|
||||
} else if ( (action != null) && ("Export".equals(action)) ) {
|
||||
%><%=BlogManager.instance().exportHosts(user)%><%
|
||||
}
|
||||
TreeSet sorted = new TreeSet(names.getNames());
|
||||
%><table border="0" width="100%" class="b_addr">
|
||||
<tr class="b_addrHeader">
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Name</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Network</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Protocol</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Location</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Public?</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Automated?</em></td>
|
||||
<td class="b_addrHeader"><em class="b_addrHeader">Groups</em></td>
|
||||
<td class="b_addrHeader"> </td></tr>
|
||||
<%
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
for (Iterator iter = sorted.iterator(); iter.hasNext(); ) {
|
||||
PetName name = names.getByName((String)iter.next());
|
||||
buf.append("<tr class=\"b_addrDetail\"><form action=\"addresses.jsp\" method=\"POST\">");
|
||||
buf.append("<input type=\"hidden\" name=\"petname\" value=\"").append(name.getName()).append("\" />");
|
||||
buf.append("<td class=\"b_addrName\"><input class=\"b_addrName\" type=\"text\" size=\"20\" name=\"name\" value=\"").append(name.getName()).append("\" /></td>");
|
||||
buf.append("<td class=\"b_addrNet\"><select class=\"b_addrNet\" name=\"network\">");
|
||||
String net = name.getNetwork();
|
||||
if (net == null) net = "";
|
||||
buf.append("<option value=\"i2p\" ");
|
||||
if ("i2p".equals(net))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>I2P</option>");
|
||||
|
||||
buf.append("<option value=\"syndie\" ");
|
||||
if ( ("syndie".equals(net)) || ("".equals(net)) )
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>Syndie</option>");
|
||||
|
||||
buf.append("<option value=\"tor\" ");
|
||||
if ("tor".equals(net))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>TOR</option>");
|
||||
|
||||
buf.append("<option value=\"freenet\" ");
|
||||
if ("freenet".equals(net))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>Freenet</option>");
|
||||
|
||||
buf.append("<option value=\"internet\" ");
|
||||
if ("internet".equals(net))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>Internet</option>");
|
||||
|
||||
buf.append("</select></td>");
|
||||
|
||||
buf.append("<td class=\"b_addrProto\"><select class=\"b_addrProto\" name=\"protocol\">");
|
||||
String proto = name.getProtocol();
|
||||
if (proto == null) proto = "";
|
||||
|
||||
buf.append("<option value=\"http\" ");
|
||||
if ("http".equals(proto))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>HTTP</option>");
|
||||
|
||||
buf.append("<option value=\"irc\" ");
|
||||
if ("irc".equals(proto))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>IRC</option>");
|
||||
|
||||
buf.append("<option value=\"i2phex\" ");
|
||||
if ("i2phex".equals(proto))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>I2Phex</option>");
|
||||
|
||||
buf.append("<option value=\"syndiearchive\" ");
|
||||
if ("syndiearchive".equals(proto))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>Syndie archive</option>");
|
||||
|
||||
buf.append("<option value=\"syndieblog\" ");
|
||||
if ("syndieblog".equals(proto))
|
||||
buf.append("selected=\"true\" ");
|
||||
buf.append("/>Syndie blog</option>");
|
||||
|
||||
buf.append("</select></td>");
|
||||
|
||||
buf.append("<td class=\"b_addrLoc\">");
|
||||
if (name.getLocation() != null)
|
||||
buf.append("<input class=\"b_addrLoc\" name=\"location\" size=\"50\" value=\"").append(name.getLocation()).append("\" />");
|
||||
else
|
||||
buf.append("<input class=\"b_addrLoc\" name=\"location\" size=\"50\" value=\"\" />");
|
||||
|
||||
buf.append("</td>");
|
||||
buf.append("<td class=\"b_addrPublic\"><input class=\"b_addrPublic\" type=\"checkbox\" name=\"isPublic\" ");
|
||||
if (name.getIsPublic())
|
||||
buf.append("checked=\"true\" ");
|
||||
buf.append(" /></td>");
|
||||
buf.append("<td class=\"b_scheduled\"><input class=\"b_scheduled\" type=\"checkbox\" name=\"scheduleSyndication\" value=\"true\" ");
|
||||
if (BlogManager.instance().syndicationScheduled(name.getLocation()))
|
||||
buf.append("checked=\"true\" ");
|
||||
buf.append(" /></td>");
|
||||
buf.append("<td class=\"b_addrGroup\"><input class=\"b_addrGroup\" type=\"text\" name=\"groups\" size=\"10\" value=\"");
|
||||
for (int j = 0; j < name.getGroupCount(); j++) {
|
||||
buf.append(HTMLRenderer.sanitizeTagParam(name.getGroup(j)));
|
||||
if (j + 1 < name.getGroupCount())
|
||||
buf.append(',');
|
||||
}
|
||||
buf.append("\" /></td><td class=\"b_addrDetail\" nowrap=\"nowrap\">");
|
||||
buf.append("<input class=\"b_addrChange\" type=\"submit\" name=\"action\" value=\"Change\" /> <input class=\"b_addrDelete\" type=\"submit\" name=\"action\" value=\"Delete\" />");
|
||||
buf.append("</td></form></tr>");
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
}
|
||||
|
||||
String net = request.getParameter("network");
|
||||
String proto = request.getParameter("protocol");
|
||||
String name = request.getParameter("name");
|
||||
String loc = request.getParameter("location");
|
||||
boolean active = (request.getParameter("action") != null);
|
||||
if (net == null || active) net = "";
|
||||
if (proto == null || active) proto = "";
|
||||
if (name == null || active) name = "";
|
||||
if (loc == null || active) loc= "";
|
||||
%>
|
||||
<tr class="b_addrDetail"><form action="addresses.jsp" method="POST">
|
||||
<td class="b_addrName"><input class="b_addrName" type="text" name="name" size="20" value="<%=name%>" /></td>
|
||||
<td class="b_addrNet"><select class="b_addrNet" name="network">
|
||||
<option value="i2p" <%="i2p".equalsIgnoreCase(net) ? " selected=\"true\" " : ""%>>I2P</option>
|
||||
<option value="syndie" <%="syndie".equalsIgnoreCase(net) ? " selected=\"true\" " : ""%>>Syndie</option>
|
||||
<option value="tor" <%="tor".equalsIgnoreCase(net) ? " selected=\"true\" " : ""%>>Tor</option>
|
||||
<option value="freenet" <%="freenet".equalsIgnoreCase(net) ? " selected=\"true\" " : ""%>>Freenet</option>
|
||||
<option value="internet" <%="internet".equalsIgnoreCase(net) ? " selected=\"true\" " : ""%>>Internet</option></select></td>
|
||||
<td class="b_addrProto"><select class="b_addrProto" name="protocol">
|
||||
<option value="http" <%="http".equalsIgnoreCase(proto) ? " selected=\"true\" " : ""%>>HTTP</option>
|
||||
<option value="irc" <%="irc".equalsIgnoreCase(proto) ? " selected=\"true\" " : ""%>>IRC</option>
|
||||
<option value="i2phex" <%="i2phex".equalsIgnoreCase(proto) ? " selected=\"true\" " : ""%>>I2Phex</option>
|
||||
<option value="syndiearchive" <%="syndiearchive".equalsIgnoreCase(proto) ? " selected=\"true\" " : ""%>>Syndie archive</option>
|
||||
<option value="syndieblog" <%="syndieblog".equalsIgnoreCase(proto) ? " selected=\"true\" " : ""%>>Syndie blog</option></select></td>
|
||||
<td class="b_addrLoc"><input class="b_addrLoc" type="text" size="50" name="location" value="<%=loc%>" /></td>
|
||||
<td class="b_addrPublic"><input class="b_addrPublic" type="checkbox" name="isPublic" /></td>
|
||||
<td class="b_scheduled"><input class="b_sheduled" type="checkbox" name="scheduleSyndication" value="true" /></td>
|
||||
<td class="b_addrGroup"><input class="b_addrGroup" type="text" name="groups" size="10" /></td>
|
||||
<td class="b_addrDetail"><input class="b_addrAdd" type="submit" name="action" value="Add" /></td>
|
||||
</form></tr>
|
||||
<tr class="b_addrExport"><form action="addresses.jsp" method="POST">
|
||||
<td class="b_addrExport" colspan="7">
|
||||
<span class="b_addrExport">Export the eepsites to your router's petname db</span>
|
||||
<input class="b_addrExportSubmit" type="submit" name="action" value="Export" /></td>
|
||||
</form></tr>
|
||||
</table>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
@@ -1,93 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.data.*, net.i2p.syndie.*, org.mortbay.servlet.MultiPartRequest, java.util.*, java.io.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd"><html>
|
||||
<head>
|
||||
<title>SyndieMedia admin</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
if (!user.getAuthenticated()) {
|
||||
%><span class="b_adminMsgErr">You must be logged in to configure your Syndie instance!</span><%
|
||||
} else {
|
||||
String action = request.getParameter("action");
|
||||
if ( (action != null) && ("Save".equals(action)) ) {
|
||||
boolean configured = BlogManager.instance().isConfigured();
|
||||
String adminPass = request.getParameter("adminpass");
|
||||
String regPass = request.getParameter("regpass");
|
||||
String remotePass = request.getParameter("remotepass");
|
||||
String proxyHost = request.getParameter("proxyhost");
|
||||
String proxyPort = request.getParameter("proxyport");
|
||||
String selector = request.getParameter("selector");
|
||||
boolean isSingleUser = BlogManager.instance().isSingleUser();
|
||||
String singleSet = request.getParameter("singleuser");
|
||||
if (singleSet != null)
|
||||
isSingleUser = true;
|
||||
else
|
||||
isSingleUser = false;
|
||||
|
||||
if (configured) {
|
||||
if (BlogManager.instance().authorizeAdmin(adminPass)) {
|
||||
int port = -1;
|
||||
try { port = Integer.parseInt(proxyPort); } catch (NumberFormatException nfe) { port = 4444; }
|
||||
BlogManager.instance().configure(regPass, remotePass, adminPass, selector, proxyHost, port, isSingleUser, null);
|
||||
%><span class="b_adminMsgOk">Configuration updated</span><%
|
||||
} else {
|
||||
%><span class="b_adminMsgErr">Invalid admin password. If you lost it, please update your syndie.config.</span><%
|
||||
}
|
||||
} else {
|
||||
int port = -1;
|
||||
try { port = Integer.parseInt(proxyPort); } catch (NumberFormatException nfe) { port = 4444; }
|
||||
BlogManager.instance().configure(regPass, remotePass, adminPass, selector, proxyHost, port, isSingleUser, null);
|
||||
%><span class="b_adminMsgOk">Configuration saved</span><%
|
||||
}
|
||||
} else {
|
||||
%><form action="admin.jsp" method="POST">
|
||||
<em class="b_adminField">Single user?</em> <input type="checkbox" class="b_adminField" name="singleuser" <%=BlogManager.instance().isSingleUser() ? " checked=\"true\" " : ""%> /><br />
|
||||
<span class="b_adminDescr">If this is checked, the registration, admin, and remote passwords are unnecessary - anyone
|
||||
can register and administer Syndie, as well as use any remote functionality. This should not be checked if untrusted
|
||||
parties can access this web interface.</span><br />
|
||||
<em class="b_adminField">Registration password:</em> <input class="b_adminField" type="text" name="regpass" size="10" /><br />
|
||||
<span class="b_adminDescr">Users must specify this password on the registration form to proceed. If this is
|
||||
blank, anyone can register.</span><br />
|
||||
<em class="b_adminField">Remote password:</em> <input class="b_adminField" type="text" name="remotepass" size="10" /><br />
|
||||
<span class="b_adminDescr">To access remote archives, users must first provide this password on their
|
||||
metadata page. Remote access is 'dangerous', as it allows the user to instruct
|
||||
this Syndie instance to establish HTTP connections with arbitrary locations. If
|
||||
this field is not specified, no one can use remote archives.</span><br />
|
||||
<em class="b_adminField">Default remote proxy host:</em> <input class="b_adminField" type="text" name="proxyhost" size="20" value="localhost" /><br />
|
||||
<em class="b_adminField">Default remote proxy port:</em> <input class="b_adminField" type="text" name="proxyport" size="5" value="4444" /><br />
|
||||
<span class="b_adminDescr">This is the default HTTP proxy shown on the remote archive page.</span><br />
|
||||
<em class="b_adminField">Default blog selector:</em> <input class="b_adminField" type="text" name="selector" size="40" value="ALL" /><br />
|
||||
<span class="b_adminDescr">The selector lets you choose what blog (or blogs) are shown on the front page for
|
||||
new, unregistered users. Valid values include:<ul class="b_adminDescr">
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">ALL</code>: all blogs</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">blog://$blogHash</code>: all posts in the blog identified by $blogHash</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">blogtag://$blogHash/$tagBase64</code>: all posts in the blog identified by $blogHash
|
||||
tagged by the tag whose modified base64 encoding is $tagBase64</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">tag://$tagBase64</code>: all posts in any blog tagged by the tag whose
|
||||
modified base64 encoding is $tagBase64</li>
|
||||
</ul>
|
||||
</span>
|
||||
<hr />
|
||||
<% if (!BlogManager.instance().isConfigured()) {
|
||||
long passNum = new Random().nextLong(); %>
|
||||
<em class="b_adminField">Administrative password:</em> <input class="b_adminField" type="password" name="adminpass" size="10" value="<%=passNum%>" /> <br />
|
||||
<span class="b_adminDescr b_adminDescrFirstRun">Since this Syndie instance is not already configured, you can specify a new
|
||||
administrative password which must be presented whenever you update this configuration.
|
||||
The default value filled in there is <code class="b_adminDescr b_adminDescrFirstRun"><%=passNum%></code></span><br />
|
||||
<% } else { %>
|
||||
<em class="b_adminField">Administrative password:</em> <input class="b_adminField" type="password" name="adminpass" size="10" value="" /> <br />
|
||||
<% } %>
|
||||
<input class="b_adminSave" type="submit" name="action" value="Save" />
|
||||
<% }
|
||||
} %>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
@@ -1,36 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.*, net.i2p.syndie.web.*, net.i2p.syndie.sml.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content">
|
||||
<span class="b_externalWarning">Are you sure you really want to go to
|
||||
<%
|
||||
String loc = request.getParameter("location");
|
||||
String schema = request.getParameter("schema");
|
||||
String desc = request.getParameter("description");
|
||||
if (loc != null) loc = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(loc)));
|
||||
if (schema != null) schema = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(schema)));
|
||||
if (desc != null) desc = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(desc)));
|
||||
|
||||
if ( (loc != null) && (schema != null) ) {
|
||||
out.write("<span class=\"b_externalLoc\">" + loc + "</span> <span class=\"b_externalNet\"(" + schema + ")</span>");
|
||||
if (desc != null)
|
||||
out.write(": <span class=\"b_externalDesc\"" + desc + "\"</span>");
|
||||
out.write("? ");
|
||||
out.write("<a class=\"b_external\" href=\"" + loc + "\">yes</a>");
|
||||
} else {
|
||||
out.write("<span class=\"b_externalUnknown\">(some unspecified location...)</span>");
|
||||
}
|
||||
%></span></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
BIN
apps/syndie/jsp/images/addToFavorites.png
Normal file
|
After Width: | Height: | Size: 275 B |
BIN
apps/syndie/jsp/images/addToIgnored.png
Normal file
|
After Width: | Height: | Size: 266 B |
BIN
apps/syndie/jsp/images/collapse.png
Normal file
|
After Width: | Height: | Size: 917 B |
BIN
apps/syndie/jsp/images/expand.png
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
apps/syndie/jsp/images/favorites.png
Normal file
|
After Width: | Height: | Size: 463 B |
BIN
apps/syndie/jsp/images/noSubthread.png
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
apps/syndie/jsp/images/self.png
Normal file
|
After Width: | Height: | Size: 155 B |
BIN
apps/syndie/jsp/images/syndielogo.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
apps/syndie/jsp/images/threadIndent.png
Normal file
|
After Width: | Height: | Size: 129 B |
13
apps/syndie/jsp/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html
|
||||
><head><title>Welcome to Syndie</title></head
|
||||
><body bgcolor="#BBBBFF"><div align="center" valign="center">
|
||||
<table border="0"><tr><td valign="top">
|
||||
<img src="images/syndielogo.png" alt="" /></td>
|
||||
<td valign="top" align="left"><b>Welcome to Syndie!</b><br />
|
||||
|
||||
<p>Jump right in and <a href="threads.jsp">read</a> syndicated posts</p>
|
||||
<p><a href="post.jsp">Create</a> a new post of your own</p>
|
||||
<p><a href="about.html">Learn more</a> about Syndie</p>
|
||||
</td></tr></table>
|
||||
</div>
|
||||
</body></html>
|
||||
@@ -1,27 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
<link href="rss.jsp?<%
|
||||
if (request.getParameter("blog") != null)
|
||||
out.write("blog=" + request.getParameter("blog") + "&");
|
||||
if (request.getParameter("entry") != null)
|
||||
out.write("entry=" + request.getParameter("entry") + "&");
|
||||
if (request.getParameter("tag") != null)
|
||||
out.write("tag=" + request.getParameter("tag") + "&");
|
||||
if (request.getParameter("selector") != null)
|
||||
out.write("selector=" + request.getParameter("selector") + "&");
|
||||
%>" rel="alternate" type="application/rss+xml" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><jsp:include page="_bodyindex.jsp" /></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
@@ -1,193 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.Base64, net.i2p.client.naming.PetName, net.i2p.client.naming.PetNameDB, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.data.*, net.i2p.syndie.*, org.mortbay.servlet.MultiPartRequest, java.util.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><jsp:useBean scope="session" class="net.i2p.syndie.web.PostBean" id="post"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia post</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
|
||||
if (!user.getAuthenticated()) {
|
||||
%><span class="b_postMsgErr">You must be logged in to post</span><%
|
||||
} else {
|
||||
String confirm = request.getParameter("action");
|
||||
if ( (confirm != null) && (confirm.equalsIgnoreCase("confirm")) ) {
|
||||
String archive = request.getParameter("archive");
|
||||
post.setArchive(archive);
|
||||
BlogURI uri = post.postEntry();
|
||||
if (uri != null) {
|
||||
%><span class="b_postMsgOk">Blog entry <a class="b_postOkLink" href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, uri.getEntryId(), -1, -1,
|
||||
user.getShowExpanded(), user.getShowImages())%>">posted</a>!</span><%
|
||||
} else {
|
||||
%><span class="b_postMsgErro">There was an unknown error posting the entry...</span><%
|
||||
}
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
} else {
|
||||
// logged in but not confirmed...
|
||||
String contentType = request.getContentType();
|
||||
if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
// not confirmed but they posted stuff... gobble up what they give
|
||||
// and display it as a preview (then we show the confirm form)
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
|
||||
MultiPartRequest req = new MultiPartRequest(request);
|
||||
String entrySubject = req.getString("entrysubject");
|
||||
String entryTags = req.getString("entrytags");
|
||||
String entryText = req.getString("entrytext");
|
||||
String entryHeaders = req.getString("entryheaders");
|
||||
String style = req.getString("style");
|
||||
if ( (style != null) && (style.trim().length() > 0) ) {
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
}
|
||||
String replyTo = req.getString(ArchiveViewerBean.PARAM_IN_REPLY_TO);
|
||||
if ( (replyTo != null) && (replyTo.trim().length() > 0) ) {
|
||||
byte r[] = Base64.decode(replyTo);
|
||||
if (r != null) {
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
|
||||
} else {
|
||||
replyTo = null;
|
||||
}
|
||||
}
|
||||
String includeNames = req.getString("includenames");
|
||||
if ( (includeNames != null) && (includeNames.trim().length() > 0) ) {
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
if (entryHeaders == null) entryHeaders = "";
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = db.getByName((String)iter.next());
|
||||
if ( (pn != null) && (pn.getIsPublic()) ) {
|
||||
entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_PETNAME + ": " +
|
||||
pn.getName() + "\t" + pn.getNetwork() + "\t" + pn.getProtocol() + "\t" + pn.getLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post.setSubject(entrySubject);
|
||||
post.setTags(entryTags);
|
||||
post.setText(entryText);
|
||||
post.setHeaders(entryHeaders);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
String filename = req.getFilename("entryfile" + i);
|
||||
if ( (filename != null) && (filename.trim().length() > 0) ) {
|
||||
Hashtable params = req.getParams("entryfile" + i);
|
||||
String type = "application/octet-stream";
|
||||
for (Iterator iter = params.keySet().iterator(); iter.hasNext(); ) {
|
||||
String cur = (String)iter.next();
|
||||
if ("content-type".equalsIgnoreCase(cur)) {
|
||||
type = (String)params.get(cur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
post.addAttachment(filename.trim(), req.getInputStream("entryfile" + i), type);
|
||||
}
|
||||
}
|
||||
|
||||
post.renderPreview(out);
|
||||
%><hr /><span class="b_postConfirm"><form action="post.jsp" method="POST">
|
||||
Please confirm that the above is ok<% if (BlogManager.instance().authorizeRemote(user)) { %>, and select what additional archives you
|
||||
want the post transmitted to. Otherwise, just hit your browser's back arrow and
|
||||
make changes.
|
||||
<select class="b_postConfirm" name="archive">
|
||||
<option name="">-None-</option>
|
||||
<%
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.getByName(name);
|
||||
if ("syndiearchive".equals(pn.getProtocol()))
|
||||
names.add(pn.getName());
|
||||
}
|
||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
out.write("<option value=\"" + HTMLRenderer.sanitizeTagParam(name) + "\">" + HTMLRenderer.sanitizeString(name) + "</option>\n");
|
||||
}
|
||||
%>
|
||||
</select><br /><% } %></span>
|
||||
<input class="b_postConfirm" type="submit" name="action" value="Confirm" /><%
|
||||
} else {
|
||||
// logged in and not confirmed because they didn't send us anything!
|
||||
// give 'em a new form
|
||||
String entrySubject = request.getParameter("replySubject");
|
||||
String entryTags = request.getParameter("replyTags");
|
||||
String parentURI = request.getParameter("parentURI");
|
||||
if (entrySubject != null)
|
||||
post.setSubject(new String(Base64.decode(entrySubject), "UTF-8"));
|
||||
if (entryTags != null)
|
||||
post.setTags(new String(Base64.decode(entryTags), "UTF-8"));
|
||||
|
||||
if (parentURI != null) {
|
||||
parentURI = new String(Base64.decode(parentURI), "UTF-8");
|
||||
%><span class="b_postField">Replying to
|
||||
<a href="<%=HTMLRenderer.getPageURL(user, parentURI)%>">parent</a>
|
||||
(text <a href="#parentText">below</a>).</span><br />
|
||||
<%
|
||||
}
|
||||
%><form action="post.jsp" method="POST" enctype="multipart/form-data">
|
||||
<span class="b_postField">Post subject:</span> <input class="b_postSubject" type="text" size="80" name="entrysubject" value="<%=post.getSubject()%>" /><br />
|
||||
<span class="b_postField">Post tags:</span> <input class="b_postTags" type="text" size="20" name="entrytags" value="<%=post.getTags()%>" /><br />
|
||||
<span class="b_postField">Post style:</span> <select class="b_postStyle" name="style">
|
||||
<option value="default" selected="true">Default</option>
|
||||
<option value="meta">Meta (hide everything but the metadata)</option>
|
||||
</select><br />
|
||||
<span class="b_postField">Include public names?</span> <input class="b_postNames" type="checkbox" name="includenames" value="true" /><br />
|
||||
<span class="b_postField">Post content (in raw SML, no headers):</span><br />
|
||||
<textarea class="b_postText" rows="6" cols="80" name="entrytext"><%=post.getText()%></textarea><br />
|
||||
<span class="b_postField">SML cheatsheet:</span><br /><textarea class="b_postCheatsheet" rows="6" cols="80" readonly="true">
|
||||
* newlines are newlines are newlines.
|
||||
* all < and > are replaced with their &symbol;
|
||||
* [b][/b] = <b>bold</b>
|
||||
* [i][/i] = <i>italics</i>
|
||||
* [u][/u] = <i>underline</i>
|
||||
* [cut]more inside[/cut] = [<a href="#">more inside...</a>]
|
||||
* [img attachment="1"]alt[/img] = use attachment 1 as an image with 'alt' as the alt text
|
||||
* [blog name="name" bloghash="base64hash"]description[/blog] = link to all posts in the blog
|
||||
* [blog name="name" bloghash="base64hash" blogentry="1234"]description[/blog] = link to the specified post in the blog
|
||||
* [blog name="name" bloghash="base64hash" blogtag="tag"]description[/blog] = link to all posts in the blog with the specified tag
|
||||
* [blog name="name" blogtag="tag"]description[/blog] = link to all posts in all blogs with the specified tag
|
||||
* [link schema="eep" location="http://forum.i2p"]text[/link] = offer a link to an external resource (accessible with the given schema)
|
||||
* [archive name="name" description="they have good stuff" schema="eep" location="http://syndiemedia.i2p/archive/archive.txt"]foo![/archive] = offer an easy way to sync up with a new Syndie archive
|
||||
|
||||
SML headers are newline delimited key:value pairs. Example keys are:
|
||||
* bgcolor = background color of the post (e.g. bgcolor:#ffccaa or bgcolor=red)
|
||||
* bgimage = attachment number to place as the background image for the post (only shown if images are enabled) (e.g. bgimage=1)
|
||||
* textfont = font to put most text into
|
||||
</textarea><br />
|
||||
<span class="b_postField">SML post headers:</span><br />
|
||||
<textarea class="b_postHeaders" rows="3" cols="80" name="entryheaders"><%=post.getHeaders()%></textarea><br /><%
|
||||
String s = request.getParameter(ArchiveViewerBean.PARAM_IN_REPLY_TO);
|
||||
if ( (s != null) && (s.trim().length() > 0) ) {%>
|
||||
<input type="hidden" name="<%=ArchiveViewerBean.PARAM_IN_REPLY_TO%>" value="<%=request.getParameter(ArchiveViewerBean.PARAM_IN_REPLY_TO)%>" />
|
||||
<% } %>
|
||||
<span class="b_postField">Attachment 0:</span> <input class="b_postField" type="file" name="entryfile0" /><br />
|
||||
<span class="b_postField">Attachment 1:</span> <input class="b_postField" type="file" name="entryfile1" /><br />
|
||||
<span class="b_postField">Attachment 2:</span> <input class="b_postField" type="file" name="entryfile2" /><br />
|
||||
<span class="b_postField">Attachment 3:</span> <input class="b_postField" type="file" name="entryfile3" /><br />
|
||||
<hr />
|
||||
<input class="b_postPreview" type="submit" name="Post" value="Preview..." /> <input class="b_postReset" type="reset" value="Cancel" />
|
||||
<%
|
||||
if (parentURI != null) {
|
||||
%><hr /><span id="parentText" class="b_postParent"><%
|
||||
post.renderReplyPreview(out, parentURI);
|
||||
%></span><hr /><%
|
||||
}
|
||||
|
||||
} // end of the 'logged in, not confirmed, nothing posted' section
|
||||
} // end of the 'logged in, not confirmed' section
|
||||
} // end of the 'logged in' section
|
||||
%></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
@@ -1,83 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.client.naming.PetName, net.i2p.syndie.web.*, net.i2p.syndie.*, net.i2p.syndie.sml.*, java.util.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><jsp:useBean scope="session" class="net.i2p.syndie.web.RemoteArchiveBean" id="remote"
|
||||
/><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><jsp:useBean scope="session" class="net.i2p.syndie.data.TransparentArchiveIndex" id="archive"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia remote</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
if (!BlogManager.instance().authorizeRemote(user)) {
|
||||
%><span class="b_remoteMsgErr">Sorry, you are not allowed to access remote archives from here. Perhaps you should install Syndie yourself?</span><%
|
||||
} else { %><form action="remote.jsp" method="POST"><span class="b_remoteChooser"><span class="b_remoteChooserField">Import from:</span>
|
||||
<select class="b_remoteChooserNet" name="schema">
|
||||
<option value="web" <%=("web".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>I2P/TOR/Freenet</option>
|
||||
<option value="mnet" <%=("mnet".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>MNet</option>
|
||||
<option value="feedspace" <%=("feedspace".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>Feedspace</option>
|
||||
<option value="usenet" <%=("usenet".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>Usenet</option>
|
||||
</select>
|
||||
<span class="b_remoteChooserField">Proxy</span>
|
||||
<input class="b_remoteChooserHost" type="text" size="10" name="proxyhost" value="<%=BlogManager.instance().getDefaultProxyHost()%>" />
|
||||
<input class="b_remoteChooserPort" type="text" size="4" name="proxyport" value="<%=BlogManager.instance().getDefaultProxyPort()%>" /><br />
|
||||
<span class="b_remoteChooserField">Bookmarked archives:</span> <select class="b_remoteChooserPN" name="archivepetname"><option value="">Custom location</option><%
|
||||
for (Iterator iter = user.getPetNameDB().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = (PetName)iter.next();
|
||||
if ("syndiearchive".equals(pn.getProtocol())) {
|
||||
%><option value="<%=HTMLRenderer.sanitizeTagParam(pn.getName())%>"><%=HTMLRenderer.sanitizeString(pn.getName())%></option><%
|
||||
}
|
||||
}
|
||||
%></select> or
|
||||
<input class="b_remoteChooserLocation" name="location" size="30" value="<%=(request.getParameter("location") != null ? request.getParameter("location") : "")%>" />
|
||||
<input class="b_remoteChooserContinue" type="submit" name="action" value="Continue..." /><br />
|
||||
</span>
|
||||
<%
|
||||
String action = request.getParameter("action");
|
||||
if ("Continue...".equals(action)) {
|
||||
String location = request.getParameter("location");
|
||||
String pn = request.getParameter("archivepetname");
|
||||
if ( (pn != null) && (pn.trim().length() > 0) ) {
|
||||
PetName pnval = user.getPetNameDB().getByName(pn);
|
||||
if (pnval != null) location = pnval.getLocation();
|
||||
}
|
||||
remote.fetchIndex(user, request.getParameter("schema"), location, request.getParameter("proxyhost"), request.getParameter("proxyport"));
|
||||
} else if ("Fetch metadata".equals(action)) {
|
||||
remote.fetchMetadata(user, request.getParameterMap());
|
||||
} else if ("Fetch selected entries".equals(action)) {
|
||||
//remote.fetchSelectedEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, request.getParameterMap());
|
||||
} else if ("Fetch all new entries".equals(action)) {
|
||||
//remote.fetchAllEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, request.getParameterMap());
|
||||
} else if ("Post selected entries".equals(action)) {
|
||||
remote.postSelectedEntries(user, request.getParameterMap());
|
||||
}
|
||||
String msgs = remote.getStatus();
|
||||
if ( (msgs != null) && (msgs.length() > 0) ) { %><pre class="b_remoteProgress"><%=msgs%>
|
||||
<a class="b_remoteProgress" href="remote.jsp">Refresh</a></pre><br /><%
|
||||
}
|
||||
if (remote.getFetchIndexInProgress()) { %><span class="b_remoteProgress">Please wait while the index is being fetched
|
||||
from <%=remote.getRemoteLocation()%>.</span><%
|
||||
} else if (remote.getRemoteIndex() != null) {
|
||||
// remote index is NOT null!
|
||||
%><span class="b_remoteLocation"><%=remote.getRemoteLocation()%></span>
|
||||
<a class="b_remoteRefetch" href="remote.jsp?schema=<%=remote.getRemoteSchema()%>&location=<%=remote.getRemoteLocation()%><%
|
||||
if (remote.getProxyHost() != null && remote.getProxyPort() > 0) {
|
||||
%>&proxyhost=<%=remote.getProxyHost()%>&proxyport=<%=remote.getProxyPort()%><%
|
||||
} %>&action=Continue...">(refetch)</a>:<br />
|
||||
<%remote.renderDeltaForm(user, archive, out);%>
|
||||
<textarea class="b_remoteIndex" rows="5" cols="120"><%=remote.getRemoteIndex()%></textarea><%
|
||||
}
|
||||
}
|
||||
%>
|
||||
</td></form></tr>
|
||||
</table>
|
||||
</body>
|
||||
33
apps/syndie/jsp/smlref.jsp
Normal file
@@ -0,0 +1,33 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SML Quick Reference</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<h3>SML Quick Reference:</h3>
|
||||
<ul>
|
||||
<li>newlines are newlines are newlines.</li>
|
||||
<li>all < and > are replaced with their &symbol;</li>
|
||||
<li>[b][/b] = <b>bold</b></li>
|
||||
<li>[i][/i] = <i>italics</i></li>
|
||||
<li>[u][/u] = <i>underline</i></li>
|
||||
<li>[cut]more inside[/cut] = <a href="#">more inside...</a></li>
|
||||
<li>[quote][/quote] = Quoted text</li>
|
||||
<li>[img attachment="1"]alt[/img] = use attachment 1 as an image with 'alt' as the alt text</li>
|
||||
<li>[blog name="name" bloghash="base64hash"]description[/blog] = link to all posts in the blog</li>
|
||||
<li>[blog name="name" bloghash="base64hash" blogentry="1234"]description[/blog] = link to the specified post in the blog</li>
|
||||
<li>[blog name="name" bloghash="base64hash" blogtag="tag"]description[/blog] = link to all posts in the blog with the specified tag</li>
|
||||
<li>[blog name="name" blogtag="tag"]description[/blog] = link to all posts in all blogs with the specified tag</li>
|
||||
<li>[link schema="eep" location="http://forum.i2p"]text[/link] = offer a link to an external resource (accessible with the given schema)</li>
|
||||
<li>[archive name="name" description="they have good stuff" schema="eep" location="http://syndiemedia.i2p/archive/archive.txt"]foo![/archive] = offer an easy way to sync up with a new Syndie archive</li>
|
||||
</ul>
|
||||
SML headers are newline delimited key:value pairs. Example keys are:
|
||||
<ul>
|
||||
<li>bgcolor = background color of the post (e.g. bgcolor:#ffccaa or bgcolor=red)</li>
|
||||
<li>bgimage = attachment number to place as the background image for the post (only shown if images are enabled) (e.g. bgimage=1)</li>
|
||||
<li>textfont = font to put most text into</li>
|
||||
</ul>
|
||||
</body>
|
||||
@@ -55,6 +55,24 @@ body {
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
.s_detail_quote {
|
||||
margin-left: 1em;
|
||||
border-width: 1px;
|
||||
border-color: #DBDBDB;
|
||||
border-style: solid;
|
||||
background-color: #E0E0E0;
|
||||
}
|
||||
.s_detail_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.s_detail_bold {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
.s_detail_underline {
|
||||
font-style: normal;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.s_detail_meta {
|
||||
font-size: 10px;
|
||||
text-align: right;
|
||||
@@ -89,6 +107,25 @@ body {
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
.s_summary_quote {
|
||||
margin-left: 1em;
|
||||
border-width: 1px;
|
||||
border-color: #DBDBDB;
|
||||
border-style: solid;
|
||||
background-color: #E0E0E0;
|
||||
}
|
||||
.s_summary_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.s_summary_bold {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
.s_summary_underline {
|
||||
font-style: normal;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.s_summary_summDetail {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ response.setContentType(ArchiveViewerBean.getAttachmentContentType(params));
|
||||
boolean inline = ArchiveViewerBean.getAttachmentShouldShowInline(params);
|
||||
String filename = ArchiveViewerBean.getAttachmentFilename(params);
|
||||
if (inline)
|
||||
response.setHeader("Content-Disposition", "inline; filename=" + filename);
|
||||
response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\"");
|
||||
else
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
|
||||
int len = ArchiveViewerBean.getAttachmentContentLength(params);
|
||||
if (len >= 0)
|
||||
response.setContentLength(len);
|
||||
|
||||
@@ -14,18 +14,65 @@
|
||||
<servlet-class>net.i2p.syndie.web.RSSServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.ViewThreadedServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.ViewThreadedServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.ProfileServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.ProfileServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.SwitchServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.SwitchServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.AddressesServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.AddressesServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.PostServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.PostServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.AdminServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.AdminServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.SyndicateServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.SyndicateServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.ImportFeedServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.ImportFeedServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.web.ExternalLinkServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.web.ExternalLinkServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>net.i2p.syndie.UpdaterServlet</servlet-name>
|
||||
<servlet-class>net.i2p.syndie.UpdaterServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!-- precompiled servlets -->
|
||||
|
||||
<!--
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.jsp.index_jsp</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.ArchiveServlet</servlet-name>
|
||||
<url-pattern>/archive/*</url-pattern>
|
||||
@@ -34,6 +81,42 @@
|
||||
<servlet-name>net.i2p.syndie.web.RSSServlet</servlet-name>
|
||||
<url-pattern>/rss.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.ViewThreadedServlet</servlet-name>
|
||||
<url-pattern>/threads.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.ProfileServlet</servlet-name>
|
||||
<url-pattern>/profile.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.SwitchServlet</servlet-name>
|
||||
<url-pattern>/switchuser.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.AddressesServlet</servlet-name>
|
||||
<url-pattern>/addresses.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.PostServlet</servlet-name>
|
||||
<url-pattern>/post.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.AdminServlet</servlet-name>
|
||||
<url-pattern>/admin.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.SyndicateServlet</servlet-name>
|
||||
<url-pattern>/syndicate.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.ImportFeedServlet</servlet-name>
|
||||
<url-pattern>/importfeed.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.syndie.web.ExternalLinkServlet</servlet-name>
|
||||
<url-pattern>/externallink.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
|
||||
@@ -25,6 +25,6 @@ public class BrowserChooser extends FileDialog {
|
||||
}
|
||||
|
||||
public void initialize(){
|
||||
this.show();
|
||||
this.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
16
build.xml
@@ -299,7 +299,12 @@
|
||||
<copy file="installer/resources/dnf-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfp-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfb-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfh-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/ahelper-conflict-header.ht" todir="pkg-temp/docs/" />
|
||||
<mkdir dir="pkg-temp/docs/themes/" />
|
||||
<copy todir="pkg-temp/docs/themes/" >
|
||||
<fileset dir="installer/resources/themes/" />
|
||||
</copy>
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
||||
<mkdir dir="pkg-temp/eepsite/logs" />
|
||||
@@ -312,7 +317,7 @@
|
||||
<mkdir dir="pkg-temp/syndie/archive" />
|
||||
<mkdir dir="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=" />
|
||||
<copy file="installer/resources/blogMeta.snm" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/meta.snm" />
|
||||
<copy file="installer/resources/blogPost.snd" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1126915200003.snd" />
|
||||
<copy file="installer/resources/blogPost.snd" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1132012800001.snd" />
|
||||
</target>
|
||||
<target name="tarball" depends="preppkg">
|
||||
<tar compression="bzip2" destfile="i2p.tar.bz2">
|
||||
@@ -373,7 +378,14 @@
|
||||
<copy file="installer/resources/dnf-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfp-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfb-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/dnfh-header.ht" todir="pkg-temp/docs/" />
|
||||
<copy file="installer/resources/ahelper-conflict-header.ht" todir="pkg-temp/docs/" />
|
||||
|
||||
<mkdir dir="pkg-temp/docs/themes/" />
|
||||
<copy todir="pkg-temp/docs/themes/" >
|
||||
<fileset dir="installer/resources/themes/" />
|
||||
</copy>
|
||||
|
||||
<!-- the addressbook handles this for updates -->
|
||||
<!-- <copy file="hosts.txt" todir="pkg-temp/" /> -->
|
||||
<mkdir dir="pkg-temp/eepsite" />
|
||||
@@ -383,7 +395,7 @@
|
||||
<mkdir dir="pkg-temp/syndie/archive" />
|
||||
<mkdir dir="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=" />
|
||||
<copy file="installer/resources/blogMeta.snm" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/meta.snm" />
|
||||
<copy file="installer/resources/blogPost.snd" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1126915200003.snd" />
|
||||
<copy file="installer/resources/blogPost.snd" tofile="pkg-temp/syndie/archive/ovpBy2mpO1CQ7deYhQ1cDGAwI6pQzLbWOm1Sdd0W06c=/1132012800001.snd" />
|
||||
</target>
|
||||
<target name="installer" depends="preppkg">
|
||||
<taskdef name="izpack" classpath="${basedir}/installer/lib/izpack/standalone-compiler.jar" classname="com.izforge.izpack.ant.IzPackTask" />
|
||||
|
||||
@@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.46 $ $Date: 2005/10/14 08:48:04 $";
|
||||
public final static String VERSION = "0.6.1.4";
|
||||
public final static String ID = "$Revision: 1.47 $ $Date: 2005/10/29 18:20:05 $";
|
||||
public final static String VERSION = "0.6.1.5";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
||||
@@ -32,7 +32,7 @@ public class PetName {
|
||||
_groups = new ArrayList();
|
||||
StringTokenizer tok = new StringTokenizer(dbLine, ":\n", true);
|
||||
int tokens = tok.countTokens();
|
||||
System.out.println("Tokens: " + tokens);
|
||||
//System.out.println("Tokens: " + tokens);
|
||||
if (tokens < 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,15 +16,28 @@ public class PetNameDB {
|
||||
_names = Collections.synchronizedMap(new HashMap());
|
||||
}
|
||||
|
||||
public PetName getByName(String name) { return (PetName)_names.get(name.toLowerCase()); }
|
||||
public void add(PetName pn) { _names.put(pn.getName().toLowerCase(), pn); }
|
||||
public PetName getByName(String name) {
|
||||
if ( (name == null) || (name.length() <= 0) ) return null;
|
||||
return (PetName)_names.get(name.toLowerCase());
|
||||
}
|
||||
public void add(PetName pn) {
|
||||
if ( (pn == null) || (pn.getName() == null) ) return;
|
||||
_names.put(pn.getName().toLowerCase(), pn);
|
||||
}
|
||||
public void clear() { _names.clear(); }
|
||||
public boolean contains(PetName pn) { return _names.containsValue(pn); }
|
||||
public boolean containsName(String name) { return _names.containsKey(name.toLowerCase()); }
|
||||
public boolean containsName(String name) {
|
||||
if ( (name == null) || (name.length() <= 0) ) return false;
|
||||
return _names.containsKey(name.toLowerCase());
|
||||
}
|
||||
public boolean isEmpty() { return _names.isEmpty(); }
|
||||
public Iterator iterator() { return new LinkedList(_names.values()).iterator(); }
|
||||
public void remove(PetName pn) { _names.values().remove(pn); }
|
||||
public void removeName(String name) { _names.remove(name.toLowerCase()); }
|
||||
public Iterator iterator() { return new ArrayList(_names.values()).iterator(); }
|
||||
public void remove(PetName pn) {
|
||||
if (pn != null) _names.remove(pn.getName());
|
||||
}
|
||||
public void removeName(String name) {
|
||||
if (name != null) _names.remove(name.toLowerCase());
|
||||
}
|
||||
public int size() { return _names.size(); }
|
||||
public Set getNames() { return new HashSet(_names.keySet()); }
|
||||
public List getGroups() {
|
||||
|
||||
@@ -51,6 +51,7 @@ public class EepGet {
|
||||
private String _etag;
|
||||
private boolean _encodingChunked;
|
||||
private boolean _notModified;
|
||||
private String _contentType;
|
||||
|
||||
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
||||
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url);
|
||||
@@ -209,11 +210,13 @@ public class EepGet {
|
||||
if (timeToSend > 0) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append(" ");
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
if ( bytesRemaining > 0 ) {
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
}
|
||||
buf.append(": ");
|
||||
}
|
||||
buf.append(": ");
|
||||
buf.append(_written+alreadyTransferred);
|
||||
buf.append(" @ ");
|
||||
double lineKBytes = ((double)_markSize * (double)_lineSize)/1024.0d;
|
||||
@@ -243,9 +246,15 @@ public class EepGet {
|
||||
if (notModified) {
|
||||
System.out.println("== Source not modified since last download");
|
||||
} else {
|
||||
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
|
||||
+ " and " + (bytesRemaining - bytesTransferred) + " remaining");
|
||||
System.out.println("== Output saved to " + outputFile);
|
||||
if ( bytesRemaining > 0 ) {
|
||||
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
|
||||
+ " and " + (bytesRemaining - bytesTransferred) + " remaining");
|
||||
System.out.println("== Output saved to " + outputFile);
|
||||
} else {
|
||||
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
|
||||
+ " bytes transferred");
|
||||
System.out.println("== Output saved to " + outputFile);
|
||||
}
|
||||
}
|
||||
long timeToSend = _context.clock().now() - _startedOn;
|
||||
System.out.println("== Transfer time: " + DataHelper.formatDuration(timeToSend));
|
||||
@@ -355,9 +364,19 @@ public class EepGet {
|
||||
_out.write(buf, 0, read);
|
||||
_bytesTransferred += read;
|
||||
remaining -= read;
|
||||
if (remaining==0 && _encodingChunked) {
|
||||
if(_proxyIn.read()=='\r' && _proxyIn.read()=='\n') {
|
||||
remaining = (int) readChunkLength();
|
||||
}
|
||||
}
|
||||
if (read > 0)
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).bytesTransferred(_alreadyTransferred, read, _bytesTransferred, _bytesRemaining, _url);
|
||||
((StatusListener)_listeners.get(i)).bytesTransferred(
|
||||
_alreadyTransferred,
|
||||
read,
|
||||
_bytesTransferred,
|
||||
_encodingChunked?-1:_bytesRemaining,
|
||||
_url);
|
||||
}
|
||||
|
||||
if (_out != null)
|
||||
@@ -369,7 +388,13 @@ public class EepGet {
|
||||
|
||||
if ( (_bytesRemaining == -1) || (remaining == 0) ){
|
||||
for (int i = 0; i < _listeners.size(); i++)
|
||||
((StatusListener)_listeners.get(i)).transferComplete(_alreadyTransferred, _bytesTransferred, _bytesRemaining, _url, _outputFile, _notModified);
|
||||
((StatusListener)_listeners.get(i)).transferComplete(
|
||||
_alreadyTransferred,
|
||||
_bytesTransferred,
|
||||
_encodingChunked?-1:_bytesRemaining,
|
||||
_url,
|
||||
_outputFile,
|
||||
_notModified);
|
||||
} else {
|
||||
throw new IOException("Disconnection on attempt " + _currentAttempt + " after " + _bytesTransferred);
|
||||
}
|
||||
@@ -387,6 +412,7 @@ public class EepGet {
|
||||
switch (responseCode) {
|
||||
case 200: // full
|
||||
_out = new FileOutputStream(_outputFile, false);
|
||||
_alreadyTransferred = 0;
|
||||
rcOk = true;
|
||||
break;
|
||||
case 206: // partial
|
||||
@@ -405,7 +431,7 @@ public class EepGet {
|
||||
default:
|
||||
rcOk = false;
|
||||
}
|
||||
|
||||
buf.setLength(0);
|
||||
byte lookahead[] = new byte[3];
|
||||
while (true) {
|
||||
int cur = _proxyIn.read();
|
||||
@@ -435,7 +461,7 @@ public class EepGet {
|
||||
if (!rcOk)
|
||||
throw new IOException("Invalid HTTP response code: " + responseCode);
|
||||
if (_encodingChunked) {
|
||||
readChunkLength();
|
||||
_bytesRemaining = readChunkLength();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -450,7 +476,7 @@ public class EepGet {
|
||||
}
|
||||
}
|
||||
|
||||
private void readChunkLength() throws IOException {
|
||||
private long readChunkLength() throws IOException {
|
||||
StringBuffer buf = new StringBuffer(8);
|
||||
int nl = 0;
|
||||
while (true) {
|
||||
@@ -472,9 +498,9 @@ public class EepGet {
|
||||
String len = buf.toString().trim();
|
||||
try {
|
||||
long bytes = Long.parseLong(len, 16);
|
||||
_bytesRemaining = bytes;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Chunked length: " + bytes);
|
||||
return bytes;
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IOException("Invalid chunk length [" + len + "]");
|
||||
}
|
||||
@@ -529,6 +555,8 @@ public class EepGet {
|
||||
} else if (key.equalsIgnoreCase("Transfer-encoding")) {
|
||||
if (val.indexOf("chunked") != -1)
|
||||
_encodingChunked = true;
|
||||
} else if (key.equalsIgnoreCase("Content-Type")) {
|
||||
_contentType=val;
|
||||
} else {
|
||||
// ignore the rest
|
||||
}
|
||||
@@ -630,5 +658,9 @@ public class EepGet {
|
||||
public boolean getNotModified() {
|
||||
return _notModified;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return _contentType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
@@ -163,6 +165,37 @@ public class FileUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the contents of the given path (relative to the root) to the output
|
||||
* stream. The path must not go above the root, either - if it does, it will
|
||||
* throw a FileNotFoundException
|
||||
*/
|
||||
public static void readFile(String path, String root, OutputStream out) throws IOException {
|
||||
File rootDir = new File(root);
|
||||
while (path.startsWith("/") && (path.length() > 0) )
|
||||
path = path.substring(1);
|
||||
if (path.length() <= 0) throw new FileNotFoundException("Not serving up the root dir");
|
||||
File target = new File(rootDir, path);
|
||||
if (!target.exists()) throw new FileNotFoundException("Requested file does not exist: " + path);
|
||||
String targetStr = target.getCanonicalPath();
|
||||
String rootDirStr = rootDir.getCanonicalPath();
|
||||
if (!targetStr.startsWith(rootDirStr)) throw new FileNotFoundException("Requested file is outside the root dir: " + path);
|
||||
|
||||
byte buf[] = new byte[1024];
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(target);
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
out.close();
|
||||
} finally {
|
||||
if (in != null)
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** return true if it was copied successfully */
|
||||
public static boolean copy(String source, String dest, boolean overwriteExisting) {
|
||||
File src = new File(source);
|
||||
|
||||
90
history.txt
@@ -1,4 +1,92 @@
|
||||
$Id: history.txt,v 1.308 2005/10/29 16:35:27 jrandom Exp $
|
||||
$Id: history.txt,v 1.321 2005/11/14 19:24:36 jrandom Exp $
|
||||
|
||||
* 2005-11-15 0.6.1.5 released
|
||||
|
||||
2005-11-14 jrandom
|
||||
* Migrate to the new Syndie interface
|
||||
|
||||
2005-11-11 jrandom
|
||||
* Add filtering threads by author to Syndie, populated with authors in the
|
||||
user's addressbook
|
||||
* When creating the default user, add
|
||||
"http://syndiemedia.i2p/archive/archive.txt" to their addressbook,
|
||||
configured to automatically pull updates. (what other archives should
|
||||
be included?)
|
||||
* Tiny servlet to help dole out the new routerconsole themes, and bundle
|
||||
the installer/resources/themes/** into ./docs/themes/** on both install
|
||||
and update.
|
||||
|
||||
2005-11-11 cervantes
|
||||
* Initial pass of the routerconsole revamp, starting with I2PTunnel and
|
||||
being progressively rolled out to other sections at later dates.
|
||||
Featuring abstracted W3C strict XHTML1.0 markup, with CSS providing
|
||||
layout and styling.
|
||||
* Implemented console themes. Users can create their own themes by
|
||||
creating css files in: {i2pdir}/docs/themes/console/{themename}/
|
||||
and activating it using the routerconsole.theme={themename} advanced
|
||||
config property. Look at the example incomplete "defCon1" theme.
|
||||
Note: This is very much a work in progress. Folks might want to hold-off
|
||||
creating their own skins until the markup has solidified.
|
||||
* Added "routerconsole.javascript.disabled=true" to disable console
|
||||
client-side scripting and "routerconsole.css.disabled=true" to remove
|
||||
css styling (only rolled out in the i2ptunnel interface currently)
|
||||
* Fixed long standing bug with i2ptunnel client and server edit screens
|
||||
where tunnel count and depth properties would fail to save. Added
|
||||
backup quantity and variance configuration options.
|
||||
* Added basic accessibility support (key shortcuts, linear markup, alt and
|
||||
title information and form labels).
|
||||
* So far only tested on IE6, Firefox 1.0.6, Opera 8 and lynx.
|
||||
|
||||
2005-11-11 jrandom
|
||||
* Default Syndie to single user mode, and automatically log into a default
|
||||
user account (additional accounts can be logged into with the 'switch'
|
||||
or login pages, and new accounts can be created with the register page).
|
||||
* Disable the 'automated' column on the Syndie addressbook unless the user
|
||||
is appropriately authorized (good idea Polecat!)
|
||||
|
||||
2005-11-10 jrandom
|
||||
* First pass to a new threaded Syndie interface, which isn't enabled by
|
||||
default, as its not done yet.
|
||||
|
||||
2005-11-06 jrandom
|
||||
* Include SSU establishment failure in the peer profile as a commError,
|
||||
as we do for TCP establishment failures.
|
||||
* Don't throttle the initial transmission of a message because of ongoing
|
||||
retransmissions to a peer, since the initial transmission of a message
|
||||
is more valuable than a retransmission (since it has less latency).
|
||||
* Cleaned up links to SusiDNS and I2PTunnel (thanks zzz!)
|
||||
|
||||
2005-11-05 jrandom
|
||||
* Include the most recent ACKs with packets, rather than only sending an
|
||||
ack exactly once. SSU differs from TCP in this regard, as TCP has ever
|
||||
increasing sequence numbers, while each message ID in SSU is random, so
|
||||
we don't get the benefit of later ACKs implicitly ACKing earlier
|
||||
messages.
|
||||
* Reduced the max retransmission timeout for SSU
|
||||
* Don't try to send messages queued up for a long time waiting for
|
||||
establishment.
|
||||
|
||||
2005-11-05 dust
|
||||
* Fix sucker to delete its temporary files.
|
||||
* Improve sucker's sml output some.
|
||||
* Fix Exception in SMLParser for weird sml.
|
||||
|
||||
2005-11-03 zzz
|
||||
* Added a new error page to the eepproxy to differentiate the full 60
|
||||
second timeout from the immediate "I don't know this base64" failure.
|
||||
|
||||
2005-11-01 jrandom
|
||||
* Added a few more css elements (thanks identiguy!)
|
||||
|
||||
2005-10-31 jrandom
|
||||
* Fix for some syndie reply scenarios (thanks identiguy and CofE!)
|
||||
* Removed a potentially infinitely recursive call (oops)
|
||||
|
||||
2005-10-30 dust
|
||||
* Merge sucker into syndie with a rssimport.jsp page.
|
||||
* Add getContentType() to EepGet.
|
||||
* Make chunked transfer work (better) with EepGet.
|
||||
* Do replaceAll("<","<") for logs.
|
||||
|
||||
* 2005-10-29 0.6.1.4 released
|
||||
|
||||
|
||||
24
hosts.txt
@@ -1,6 +1,11 @@
|
||||
; TC's hosts.txt guaranteed freshness
|
||||
; $Id: hosts.txt,v 1.161 2005/09/28 22:54:30 jrandom Exp $
|
||||
; $Id: hosts.txt,v 1.162 2005/10/27 20:13:10 jrandom Exp $
|
||||
; changelog:
|
||||
|
||||
; (1.184) added sion.i2p, betaguru.i2p jnymo.i2p always.i2p gonzo2000.i2p
|
||||
; flipkick.i2p mindisl0st.i2p torapa.i2p wahoo.i2p badfish.i2p
|
||||
; slack.i2p bobcat.i2p pycache.awup.i2p lp.i2p amazone.i2p
|
||||
; inproxy.tino.i2p kohaar.i2p
|
||||
; (1.183) added ttc.i2p
|
||||
; (1.182) added tracker-fr.i2p
|
||||
; (1.181) added syncline.i2p, cerebrum.i2p, news.underscore.i2p,
|
||||
@@ -445,4 +450,21 @@ jazzy.i2p=CWHSDlZ4DKnngu84vCPRJnB3cgODJ5YWZEFX2GugisWCKjSYudJkvzfZ0eDzNNXfhY8l28
|
||||
trwcln.i2p=-4anDxCTGt6UIOoG~G6dKY0gyaq9qg-wH-TimOpbwf6zbuktiwYXuLcg~fScqyfZjdAEQoS3d8o67wPq0oBeZzXZGppmhP7wYmeLYmc9cYTCwGavZ7WGMvBnNR2TCCfymeVKIQFWrY1NP8z5YXKpUMywW0M5BSupx6ik99kG2W7RtEU~Yr11EF0MsS-~Fr1cQp2YvxHaUTBVmkG1RzkM7S5udlWcuCoRQsgDJlfNIOSEekTEGVls9~gwP4L8-gD6clXP3pRWHXnnbjtS0mY~A7Ci7WErS5w6Q7X6hiEB51DWSUMWZ~2LkUGpKj7n-I~6nx8jbSqKV1r3dQit1hJ-F5h5GOyXH1jgUtF1SpagQ~LzCVj0Rp5396DVLcckzlwhtcFYH2mPoHVgxliO1wU-zU99iNnGACrOyCv7gpQZjyFh8WKa4r~vGvyYWEt9VSp6W~Z7GeCgh7Bjvf9fx9NIBa2vqQkaj0spGg~yxSGXKboNx3dpwknhzRPioZBRUZDVAAAA
|
||||
tracker-fr.i2p=iZ67Ba62MzXPtQGoMDU7lrDaiHFDrCebwH2cLD0ll~n6i~4sw-yoeHx9mw3x1NyxiTifE7k5Dhr0IF33ry56BwbK-PZOJ3j~nYKBcfZrj4JsTzWH2c3NjlXs1nOUoWrpSrzNO-dzZLO50U7Kh3cQJHukovTfnT47SMHpkwDZ4frNIz0bAmO81s09yzei1bdufuHC63-xjvPVdsUxnV4jCht3skV0P0G~4VCT5vVuYjnD~BXAI84xjDDFOwxq3V9ABKhtO9qyi9n06hVLVK1aaPKSo7ieWGrGXQyIrauwhBEchy08MrrtXa1fsf9XpMl5RkDgUKSejrVzpKhfHexubwozyuq0o8sX6HJZ8qvl-lZhY9v6L16f0ibLLMTZPZmrOKwZaOYItR86~-7pw072rjVMnFuVc4ZjLkTRu2ljlkTY35Oj9Ck9dp-sn63WEO~Ec-vI8KKc9Q3E2Yn1Ckys-Qn-Q1uMCrwrfoZL-OMn7lXTumnH9yoE~7p3Wk6JE4f7AAAA
|
||||
ttc.i2p=rVaxsiggLlFY9mtmSlNZT5vuWMydT9V03gRwE0IxFtofadYj~5U1V1M7DBwP627UjFLurUOvN8EnqlqusvsbmFvQkY5Y-yoBD4YViRnzPav90GmoaPCOUPW~UQdHXRswFCB19c8p7o79UCjm77doTelkGDzZvUBvAVYyr2BKG1r2rUPzFOjYHYxVfNBaSxXc07e9syRg0aCcbTamknN4Vb1G-mQW1F5c~3Xo~5rHpTQeUbtW-v~PJer5fSKMHNJmq-goEd7OzM~IAfMXvKwz0uEi~YLl8B49gJpbrSM3Rz1C3PbR3i-Fsg4Bo7YFxvzFKyhgRhVjXqbeevXY61xxVR-PWTj742h1Lt~TCTe4GDcM9o1oJKIIIly2R46eIU8xSH-52hiWVh7Hb9IT7SEgd60rVE11DVW7htfDBNNL7Zg~yHiSZMrKXTid7c2t9cehCu2jwkvwu0y~CJsVfhulKCyP6m6nhy3LtIWHPLVGhTYetsHPq4NEj92dt6gKXM8cAAAA
|
||||
sion.i2p=rM~3VaoSq~ou4zRy65SIHaEg6XDu-bzl9GOt9nvQVlBevSMAEpNzrNz5sgyLt2jh4BdT3Rwey0FcyAnjRz80qdwQvK8bahkmPfyFfCtFvG~h5zOQ8D19jas5~R7wxTQPvzK3QoE~FUpY4BZ1HHBQtMIszMQRE2cU93P5N9ShPbFfRm8swJfIvgdAfL6M9VhHZqUWVOAbiN9U~WqKevPdomtSQmifRXUXVpokxrxxbVX-8BnxFIqfrJW5btceWoo-9eydSgz9KU8qnLExDZ55GGYzo4e2GsdqRy~Q7jgPA~hCD2WFFmV4MY7WY7zoMW8oLXPnODBb04aSXSPVGtLj~RYhRRbNK9Y9sHwnHryuJ3G1TnSyDV2xHuhAxzR~t2j4GodzPIHEnn9sUXuuc2w~O3u8fz9svkMERMKuRXOc-WtTMNPW8LmG8mrCFIaG-BR37jS0xQyKhJ~FkUMK4ss99w7fv8-98Wvw8LzeEY3JMRZ8hnR6p9YK4~owxrYXCQF3AAAA
|
||||
betaguru.i2p=4jSEmLrl6UTfkimwvq3BZAKjMnsWK-Tr6n1j7TfGY~g8Oh33G2~GPrvygjBJpBMP5vl5yc3GPhaqksCebXYT6HMJomtNYzDBzzlTRvBzz3WVj1bK8ubGlq8XWyWUzsdaMAmGBJBK7fr3qvNs-upQuYQnOid-0UC9KryGBn7-9cW-bnhKi2vdWQvVZ2NkIvC7Q4e3lhdVNa283FF6FxQ4kAf8-3V0MTaPxuAvIot3cvCG0L82ZVZ3vEgeIy2Ab5fNR8lxSgp1ewTqsBcNIchhpxUM2QpsOPUisnJqZJKjyLr8pIGbVFCLgw1dx7kt-tdhFvA1w57zRnsldATy7lsiKTVjzIN5W~IFw7CUBEsbY6QPnaH7ot1pzTIEoRn6A2aoakNMNp5gTgyCAKU2css2sqngcs7ozhecZATFXikDrQMj6mwNpG6yC0ffTY2JcChf6U9P7dij7e0hy6bucOXd3cj~g2amNz~F9IaMXZF80nxpMphUDXIN9VthED3KeRyTAAAA
|
||||
jnymo.i2p=-jNuCBe5REPJPPc-KKWbZXc5SXjwkqpn8EHPpIdk6wMhS-2XSsfdXgw9giUhCiVz3N1udj5xgmQYSlwqxvBkb899gBV-vpGzLDz4KRLTVl7PhShlJq2TDM61y4IACX6XeKw4xPPh5NJF8Oa3MqzRewY1HSSpSV3YOjKGRTBjdXcpYFUoT0gglcBrPHpptWVY89GkPMvD4bUiWZBasaWgV6Iha~0P9b4ZNyw12Kl1mIxv-Qk0rF7-Yj66uoFxBqIao8oMdX90qnkhRNSP-LERNsv3pIOQbZDjciLMN1NFsN-BbrHaSOcPBhhgX0ugWjZk9WeIanj4B9gEwzHiepkduEpTwkrSWIKMGPyZfIMyLb4~89FpGFD9A79bi-IFhBTCu~UlC8oq5F8~fD0V-ruz4v-tKkHu1T7IA3WRn~9T5BBDx3ZasuvzMRLIh6txd238HeF1KfwgTo13v7GepfrGbXU51AsRyChzlkKrkD0heJPubdeOrH9157eGuTcCxPF2AAAA
|
||||
always.i2p=x1aKRhVYG8cSbrfVxL3fNwJN-zVWE3VXHLUHoewf05xNzgOFZVTBHYpkV3yHxQyML~J1KLoEf7CEGF40mX4jUJfxOrZRlVWUL9e5gPenH3xPs77rUbbflqP2cY5VueZEpuN-5cLtWQmczYrRiDCcwCwuaQPLNzO1Ra~8YZxQM6is5fYHznsn8TvksQ6ShdJKllX6Je~i3OBdjMkMs24O-fErxtZwbbjzqX0FONV8W6EbGtDb5rAJdqSO8RkwKjogd-77js5n08INhRdBM8uhvFrG9M~~rkG7txS4Zgo-rolKkSvVK0Ezcq1MDKfRq9uklqTbbjCSlPjyw66q2XAS9oh9zphp5vtGBxojcnA~qrj5GX10j2TZM~TE13eaXF57za0SIjN27gAOTwmDL1HrTrKNzD0RFpQLFmqyr3PutCUMNhVfZugskTpvzw7jOHCWyc7c168JArM4U1KnwlsD~5EyaZRYj~feflUpF08MV26mct2aBCXXDAujMoMn6rUtAAAA
|
||||
gonzo2000.i2p=x4CMrOV~LKqBl6mwTm1nvU7xl6MEnk~gVuKRJCLUZhnbS4lmcxH90bCy4d~VHenU8oQvURQsCsTnW-vTZu3tQJe2uo9s3uMg8ZRXR0oGOHjBbiO-lHf7uT5quSCKO-qe6AFfCPT6aj0nuK4zmb2hUMN5Me~y6xSe~GTfLEKfiOfVkla8L83CUDMLrUfCoS~jZKa2olJnyaF0lcUeQn2DLLMDmce0KYBuAc-ORkSPykdz-UW2busfJFQOBq2P85clj9QhlVrj2LJjEYBOt4kZv6qle22e7lTlEkCLPZs6mqKBres5Xe6yYowyEKt5Y8gGOQKdnUVxSq2Y~S8TCjsvsXghZtCeXzP21o8Sih6Hnh3Ae-n~Amro-WeovKgCjMPniyIeHS5jK0H~Qp-Txij9BFP~IfDdkret9W~z-CjU~t1VQOfdAaQSyYgGLe5OIBZ0l5pe8OI23kv8RRjnoQ94DqitBCgQUsPhTavt7GiSUMOD0qklq3jDhM2o74M2JVW2AAAA
|
||||
flipkick.i2p=6wiuds-WNX5Y3Lj37uKtZ4-3AU~D6-RqIC1GHRY~Efm0DjrinM5B0YKJIcNLXBwZnshAqV7g6Sfv~F0qYwRM7Y8v2QexStzTNZCY8TTLeR1cto9x0IpSevMHLK8MqJYaxh-3s7TLEJ5hjVy1PdoxZYZQJXjFKfdQkDbSLnXH2wKlXwRwo2Jjsd0Vr6aadaD9lL-XpKW9GTrlreK1sa9Q7Hzyb-5ND-Xjiz6gO1zRADocddLukq--FLejEakW~y9o7BsurTWPwlUf2bmoZRiSKScJr1lu0vKWFDNnbkraL6RnrtFOuBkcaknc8mhyzqI6Lrwfcw7OxM3IqmziVpOJghzp6kgS3frt~mUQriFIDQ~Bkb-bTQbl00JOAF7WkpP~4V1hA0prS~-j23bkhs-5t35Zqeait3MIerY6HGU75uslNQaIP9JzvAc4xlq~YLMgBPFsmGPlyc5x2cqJbpkqzfy-DgjpcGkgelt7l8XaDfp0UUmlGkTnI9qr2TlveH-5AAAA
|
||||
mindisl0st.i2p=9WFsflqlhhWEV6KWOo~JzPMYvteJnTle9uIJp79dPJSfbm6Vp97~KujmnAxYPSBN7Pdp~J1v34hbzU9oHz9cOUsGnnHPYiw27GQOP~1Gkz4x446s4QZVLI~MWaZR3ewCCnhVLdw9c1XmVWxiP5HrGJA1qky9fa7dyZPUHOliEE9dvRncbrcOivoqJi~YARLIdPLQEI8ttbIiSpzsHCA7Kh0VcHPW2MzCMUPCojj-QPTItSdhX2M50ox~oYD1WL7pLnmThf42Xlm13dR~42Z7AZoV4PRa2tvxcL0uU607iRjEfDpcYwsoZHk2BvtX-dvdixaEAgHfGOsMF0ugHrFg3xf5~D-vv99KJQrmO0I8Xn4LQzroFS6DENmu1smyM-JriK70aEs5SZJi17NPZqVW1VBm2-0XRX0odsl9uYSWOEajZgFo9c8l5657DXZqSqQ26Wa7~gpqN8cGd7xlQTteAz94VK1xybvvOYfjv764xL-ik0r6ZMlCFkGOgKlsCQ5LAAAA
|
||||
torapa.i2p=7-OZ-cgRTCzKcAtBYEO8d9dGA57~5SjyNicI-5VNPxwW3rN~CbXsJpZ~oSrwDjdUHN5VwgnHlI1pHjon~DsTsk4Fg5Q-x3B1MIx4K2alBOCYmgkf-SJWurlRGn5-YbhD3jLcCSWPAYcDLpUNz2a8O23m4LwFIxQg8U7MRFlRm~4954MICiGWPaS9nfSJXs1dQ-zLWynAFOrvTg~nR06XofgTD7hm0pRFg6bzm8PIwlWz4~ijIPHHOxdN2WvB6aWkY-LxFVcBJPNbknjkplgofs-U2bySw7B7pz~-~Mri9jN821ttA3JlTurtm2mf5imDrGtWu2jOXYUMAkGRHPbFw4~GFfzUj3V2xHYby4ENgnB8YQINyh0XxWeUYd4MJsFVoHXvmHXBFcE2nNMRpz7z7MWYqxePZdHx8CCDjWsCKy8u5KfBbeFNGC~AFAOGYWvyCnCAeStI4egPEhRVKNm-EKXpUi3dNLKKT4rp8nN97WPe3zbzx3f6pIuruikG8PKPAAAA
|
||||
wahoo.i2p=PGYgUXHEruT-4JkVQhzMNWleVlcql1F1MoczioBNNlQIL-tYUdL7ZKfxim55JynmOKA80w0qg13gKTmwfENdphLXOWSThApMHHoCo63EHcmlKJgmIA~-I8uZd~KhLZtM-NefnmyF2QOFXwMk4N0Asohhyq0oUMJrO5YZYF-VxpniBP0gra3VXyuH0XxKODjG8bhx6p4olZa5ALQOOLBWgvYt1kO1xhSP8Q0HaEHC7pV9bqxSOlIUGDhb65LPzQ0y04d0PV0KHKWASXb0sv~sPe5NUTTGp~lkkFFxi3Dkrx2nlhpHwT5fmVcbUTIP8rklOgxOYw6-vpwtsmEZ1zFqEzqy49FbuoXXWvFmIVMFx1xUBO~w2ibmCKEXWm7lRMv~VRMhAn-bFVPnOnyLru-jsqnGvM1rJBpiIcd9GLK3sMy1bZtYKqgBhJqRjD~XB4E4YTLTu087F7kUU1FOoTpBXPmwkOKL4GAYIbn98g7qvIXVk719ME2GaeC2ZHpNMYPyAAAA
|
||||
badfish.i2p=lho02Nd5P~CelAz5Bd5cKOo4hBgrfFXfv2g691UeAQc0VDZe7pWNJiZ8yo0p1nwO~MbEektfclOsbXgskv5-RY7V3VrYlxQYxvHdW~04IqyEdXu4JMfpZeLiIkAPrNkj5aBlafn3euWrWWKuN3rEuBDk8nsewRyGyO6h198CZI8AZTO5hO6DbqYNV4njBgJ7UqL3WLNYRWOtl5hTl7tOYYImlMgOeEj0PqDEhX9ao1ypj4SAC0weMvxnXvchVmHvdWpH0fuV3h9pEBjEupfXz~7c4Jnn-kD2JZzajbP3b8Lk0xwvut1RiaflD9FoMagrmk7njaQcASLhtqgThxS1LCdYj76Imdmc2NMhzxS6GHEKR5WKyQGT51XfpJeB5P50zczQ2se5GmK7wOcA07rnT5JrNmrK~9HroK0hdD~v2SYh~~koC9e-O7NcNC~J2oWI9M5B0K3IUrF7eJJ7QBeENELjsep0sAddcWTfzeVjumPLrg7yiVj340j-AMYIuFIUAAAA
|
||||
slack.i2p=XgZi-E3IIoCV1UPwfuG-fELOpx7W78RB2FdwMRI2C9u3laBHAaAJPuc8q2eMO9XqaRFRhlwoP44jkSoDBDWsMvyfhLGJvT8CjJYDm2LVJXKjp1qEgk0bfaZ2b2A4UlulMCT0WGFcEuAXmTyfxr4gQpOTDVyuTPdcXL23quAxOiXYB-PPIyGDQdEP2I6gX842ZlxtgQRO1pmSt7RRU2paqiz0iyVfawrQkeAsVxs3KC3qIj9XRJr1bYwQVhsW~2JfoUdgjDlDXIo0npV6p8bdT6BaQ3JqHU9fUEbkZbYet2mZlZJo1K0Mz1E4IH0vmC-2j~~IvJ7PY0EcPXW7qW8gRhmwSfki3MfCih6LxKoGq6vNvI-UH1g7WBvhZizyaQvya0pUmotFcNZoixdAcWvUS~2WO5YJpxc~-6zfc~291ZZKn90ECVtXNV0TbCPE2Tpvjj5-4jv9WCtxFRqxvjEk0pqBC3P27D3MzMZtfAROkMgoxBrbn-7NyeVx93Wg8MBEAAAA
|
||||
bobcat.i2p=jzoOGTrv4ieSpwdLu3RbUT9FCMb8ZIl7x-yGzqFg9DRflEjI-VEo-2Im5XxVEQFQn8xApy1I3Ih2n0XUTTNwOmpjZnhHZRcOPbdzNvpnl6VgTqQT9LswZK1h41F26eLAm2iEwK8TIsmJFA0IVjVFWym7By-IR2D4uU9V4BNObiFxdi9XhVv-yqWNnv5aR-WjZ4A~nFaxDMyIJbR9lKeYyTWIR6Dv4DmORlET3H2RMDEGOkhskme62sd9wE9JjH6F1DB1lpWc3ohAq8EJlRt0SsQHiqOyz3e0WCol4CDkWZbfGUY9-c4dtCDdjoG2MXso0WUvs7G0b1jRGBwNMP4tHm3xuictlWfyj7AM~awY79u499nEYMVVq2e3rUDAOIWJOYH5kdj638BYOz1yVygkwjhDKtzN6SHpV2fuDSANhIy1-3gpskXlnNdBD9yQ7FQ6XZetNxTrTs-I8amYvbwciglahC6f8TNJvt1eJ9j1wfx5aRKNLgE0xO2sj7f3GyMOAAAA
|
||||
pycache.awup.i2p=wjdDY9jrPgSSO0F2-2rLv6wBoixGcwDp3JS2nPtb6CMYICZ0Y2Zl3qthimcglKogM6Y8LRuqvKi8l9N3gW33ZqbPam4ALTPX1t-lrB-Eq4fOG3Q79axtVeC3DUOUr85eUNPATo5h5lwbpiQTqIFPrifxyAmx8sNSkLxHBmxtwvO9hLCjquytl9Zvqgkr-XAfx-uaZ7bP~MVDPU137GJ7vYh2b106mbfYfRVvd3CjVUX1~QA8p0J2z0UhUr5Dw4A30BltsuoIjHUJPHTg4GKMu8aN2dmnZ4MQd9FYtPcS58hmav7YTZwWOE7iOiEV3uDOybuDTBvUr~jqnYfzBojhRXGQr6B507v1LrsTQK1otsCbJueXJD8PRL1BtZnZY9HHmSHhMkvJaN9ywuU81sl3lARBYqd2kZWKvRWVrbcz937guBg5NyrdmNLsmcqjQRBiiG2c4MnCJBNjJu0yRY7XnBaPPNpZUc-0~2E6BMa5W7Ofr0U-93HQ9VehzfcLZtwLAAAA
|
||||
lp.i2p=9GCeBnLXaOgCDUrkzxaV3MxB~k4M7AM~-5YROP51QyzRQ~MohC7P20vkfJrIa7CU~5ZSpYLexeDonpNPOQDX4qNIFaRAIWjYp29YCarptYceC-5V-lYh~eFxbSgFwOEsN0jUUNfDDTk2IAFP0xtdt4UMPffp0NwRS3g8eSO81GDDNCu5P8Te65f1LNmBWE5nQ3z2I8pzhdJY54VP-1bKmJQ58l--ARJvk2i-uTiZNkH4mLv4Mxnt311OFCHc0Jt9TMTZC-nwC4rbmPzHUxV98E0U1bizHteSmWeAch4hEp2fhdPATMUxStwgY0ZdSH1zcmoNYpxxeiC6b2bhtanoijTLxUdjFiQDYwR8R4z9Riqnj9sY4u~eLCcinqnJ-izJu~zLC11mpWUmthFlmUJnNE3AqNeojPXverT07MGCnZ~282MmddQGT~jitTf6ETS1RBYYewrOlv10u~utL4DvTV-umrqmcltZvFC6og1M7V8lwgbyegYOWWDZFP1wcDiQAAAA
|
||||
amazone.i2p=KloqmDOtO35jYgefz4gmjyaDxSviLGY0A2ZeQyvDKuhVD1BaROvBTLMp2Z2rcC~hVFJkus1UVSFT0fDwQV~is8uYpcfrKal~EUTbV7uWOelwSJFEJBfoIfJ-yj7hfd6kC4Hb0tMudMLnaRmLGVZJ8o2FGTkNmvItZMPXlc6E8DjfxgegvYcdx-BYDaOvJUyD6322xaRyVDJmQc4OjvCgw8fzS-m-3V1eHkfx4UVeoxKy~tuckKXLd7VVVXNijoHG2PHNVXinfMwopUYzPyqsw9n9ucqLZdskXgm9O0BAuCJVJNCVmBQNBzRt8bX-NCypmISU7MN5YYVPumh-duuTPEQsZcks5JixtWlkIfzON~TZ5PaDlUPXvLgdAyKfWbNXBCR9nfE73KkpienPjn4-XAYupkRm1mG80IiojtViGjFAWnyP-awHQGPj0fURPvQvPu~RVTpKcI6x0QaUdd389N-QYjnBA6dJCRx~JrHjUP32GmWM4qNNLwUumo3za6DxAAAA
|
||||
inproxy.tino.i2p=gNVJ0hpqZafnYkh7KFVHcvHuE~DeeOPZ45T1EFc8ARtd41s4dzKKaADtCtAmQIgQ8UYaiXA1l9eahcGP2rfJ4y3Ap4n3t-kext4UpCjzfwdI-u6s824nUb~ZaNfJIlqhu4sjmN0CK87BwKWU4-fYv3bM7mDDPWFT70ret81nN-SA3dQleKa65EK1T6EjKvAWeWkMhD9KnlsSMCc1OHwKX9Z8rM0Q8uXSYCLiY8VfQDPwOINvpTFUnuToo8GZ3KLQlECIZbE9OVJZ-0ZZEny1Muq~J~mQydFQnnCHB3hvPxjuv0rtO25zsBrAy4oFBrGgaFqy81gfTGDKhLwjaJ4hyYZwjBUNK5K-XLRO6ev03iOcVMvfuEdnCb~3uEUxEGYZTcAFJMUhSswo9CquLe0BodHm-biyki0kPxf~vE-yiCj0OPsUSD6frvqSqpksmAlasBhgQXR9hCJ37qJF1tBT2GaoHlHVhHzMqdNDEUHk-R1WRSeTghRDpwhQpCKb8VThAAAA
|
||||
kohaar.i2p=2qYXoTui18BY9KtzFiMsdw6-8-rZbeSoEMkVkFzYCP-ztPWp4p7-d-6d9Yjkjo647iqTA2DYcQqIZfI8V9gG7Q0NwpC5AHbbBz~117YPLcm1uf13m7nMiXKy66qzsTC~AzIazw4EUCuCTyubr~SzYrcX3M5c0ccl~ltZrnr233Y5B4zt5-6tkckXYLuOJVXfNhRLOAI-EQ~KGP~MxSWiuItDQW7DFo9-zEzN8J0sdiIHW6XcELDWth02PbAGOyi6OlJFfj53oF5MHPLMnR~o50mvu0wWtlZXR7bOcaFonfcfHdoV-m5Ilj9H5tNBdspg7Gimx3HBW8BoUXkxWoJu403mLHNXOhG2Zw1uK9bx2GJdrkMgvFKyQn9iq2USensMrb7Wf2LgFzc0lI5BsR2BTTp~cB~u1HHhXKlVYSxYKPxpjls6-n7bynIe9NSE-ToAvVOJ7ygW8sKJWxNu3tA-8ZSQ1kB4IRpzT901Nng4lAq4aMYVw8l2Wvo1SgALqUNJAAAA
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2005/10/14 08:48:05 $">
|
||||
<i2p.release version="0.6.1.4" date="2005/10/29" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2005/10/29 18:22:11 $">
|
||||
<i2p.release version="0.6.1.5" date="2005/11/15" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<info>
|
||||
<appname>i2p</appname>
|
||||
<appversion>0.6.1.4</appversion>
|
||||
<appversion>0.6.1.5</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
</authors>
|
||||
|
||||
42
installer/resources/dnfh-header.ht
Normal file
@@ -0,0 +1,42 @@
|
||||
HTTP/1.1 404 Domain Not Found
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Cache-control: no-cache
|
||||
|
||||
<html><head>
|
||||
<title>Eepsite unknown</title>
|
||||
<style type='text/css'>
|
||||
div.warning {
|
||||
margin: 0em 1em 1em 224px;
|
||||
padding: .5em 1em;
|
||||
background-color: #ffefef;
|
||||
border: medium solid #ffafaf;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
}
|
||||
div.logo {
|
||||
float: left;
|
||||
width: 200px;
|
||||
left: 1em;
|
||||
top: 1em;
|
||||
margin: 0em;
|
||||
padding: .5em;
|
||||
text-align: left;
|
||||
border: medium solid #efefff;
|
||||
background-color: #fafaff;
|
||||
color: inherit;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class=logo>
|
||||
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
|
||||
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
|
||||
</div>
|
||||
<div class=warning id=warning>
|
||||
The eepsite was not found in your router's addressbook.
|
||||
Check the link or find a BASE64 address.
|
||||
If you have the BASE64 address, paste it into your userhosts.txt using SusiDNS
|
||||
<a href="http://localhost:7657/susidns/addressbook.jsp?book=master">here</a>.
|
||||
or use a BASE64 address helper.
|
||||
You may be able to find the eepsite's address helper at <a href="http://orion.i2p">orion.i2p</a>.
|
||||
<BR><BR>Could not find the following destination:<BR><BR>
|
||||
213
installer/resources/themes/console/defCon1/default.css
Normal file
@@ -0,0 +1,213 @@
|
||||
body {
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
text-align : center;
|
||||
font-family : Arial, Helvetica, sans-serif;
|
||||
background-color : #FFFFFF;
|
||||
color : #000000;
|
||||
font-size : 100%;
|
||||
|
||||
/* we've avoided Tantek Hacks so far,
|
||||
** but we can't avoid using the non-w3c method of
|
||||
** box rendering. (and therefore one of mozilla's
|
||||
** proprietry -moz properties (which hopefully they'll
|
||||
** drop soon).#F0F3FA;
|
||||
*/
|
||||
-moz-box-sizing : border-box;
|
||||
box-sizing : border-box;
|
||||
}
|
||||
|
||||
div {
|
||||
-moz-box-sizing : border-box;
|
||||
box-sizing : border-box;
|
||||
}
|
||||
|
||||
h4, label {
|
||||
margin : 0px;
|
||||
padding : 2px;
|
||||
float : left;
|
||||
width : 150px;
|
||||
height : 24px;
|
||||
font-weight : bold;
|
||||
text-align : right;
|
||||
font-size : 1.0em;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing : border-box;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size : 1.2em;
|
||||
text-align : center;
|
||||
width : 750px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
form {
|
||||
margin : 0px;
|
||||
}
|
||||
|
||||
textarea, input, select, button, a {
|
||||
font-family : Arial, Helvetica, sans-serif;
|
||||
-moz-box-sizing : border-box;
|
||||
box-sizing : border-box;
|
||||
font-size : 1.0em;
|
||||
float : left;
|
||||
}
|
||||
|
||||
input {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #F0F3FA;
|
||||
}
|
||||
|
||||
button, .toolbox input {
|
||||
border : 0;
|
||||
float : none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border : 1px solid #ddddc0;
|
||||
}
|
||||
|
||||
br {
|
||||
clear : left;
|
||||
}
|
||||
|
||||
div.statusNotRunning {
|
||||
float : left;
|
||||
width : 78px;
|
||||
height : 24px;
|
||||
overflow : hidden;
|
||||
color : #dd0000;
|
||||
padding-top: 24px;
|
||||
background: url('images/console_status_stopped.png') 0 0 no-repeat;
|
||||
}
|
||||
div.statusRunning {
|
||||
float : left;
|
||||
width : 78px;
|
||||
height : 24px;
|
||||
overflow : hidden;
|
||||
color : #00dd00;
|
||||
padding-top: 24px;
|
||||
background: url('images/console_status_running.png') 0 0 no-repeat;
|
||||
}
|
||||
div.statusStarting {
|
||||
float : left;
|
||||
width : 78px;
|
||||
height : 24px;
|
||||
overflow : hidden;
|
||||
color : #339933;
|
||||
padding-top: 24px;
|
||||
background: url('images/console_status_starting.png') 0 0 no-repeat;
|
||||
}
|
||||
|
||||
hr,.separator {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.subdivider {
|
||||
display : block;
|
||||
clear : both;
|
||||
height : 10px;
|
||||
background : url('images/aqua_panel_hrule.png') no-repeat;
|
||||
}
|
||||
|
||||
.freetext {
|
||||
width : 150px;
|
||||
height : 22px;
|
||||
border : 1px solid #aaaac0;
|
||||
}
|
||||
|
||||
.control {
|
||||
margin : 0 4px 0 0;
|
||||
padding : 0 0 4px 0;
|
||||
overflow : hidden;
|
||||
height : 24px;
|
||||
width : 68px;
|
||||
font-weight : normal;
|
||||
color : black;
|
||||
text-align : center;
|
||||
white-space : nowrap;
|
||||
background: url('images/console_button_sm.png') 0 0;
|
||||
}
|
||||
|
||||
.control:hover {
|
||||
background: url('images/console_button_sm.png') 139px 0;
|
||||
color : white;
|
||||
}
|
||||
|
||||
.control:active {
|
||||
background: url('images/console_button_sm.png') 69px 0;
|
||||
color : white;
|
||||
}
|
||||
|
||||
.panel {
|
||||
width : 760px;
|
||||
margin : 16px auto 16px auto;
|
||||
overflow : hidden;
|
||||
text-align : left;
|
||||
font-size : 0.8em;
|
||||
background: url('images/aqua_panel_background.png');
|
||||
}
|
||||
|
||||
.panel .header {
|
||||
height: 36px;
|
||||
padding-top: 4px;
|
||||
background: url('images/aqua_panel_header.png') no-repeat;
|
||||
}
|
||||
|
||||
.panel .footer {
|
||||
float : right;
|
||||
height: 30px;
|
||||
width: 760px;
|
||||
background: url('images/aqua_panel_footer.png') no-repeat;
|
||||
}
|
||||
|
||||
.toolbox {
|
||||
float : right;
|
||||
}
|
||||
|
||||
.rowItem {
|
||||
width : 760px;
|
||||
float : left;
|
||||
margin : 0 0 0 0px;
|
||||
}
|
||||
|
||||
.comment {
|
||||
font-style : italic;
|
||||
padding : 2px 0 0 2px;
|
||||
float : left;
|
||||
}
|
||||
|
||||
.text {
|
||||
height : 24px;
|
||||
width : 150px;
|
||||
padding : 4px 0 0 2px;
|
||||
float : left;
|
||||
margin : 0;
|
||||
}
|
||||
|
||||
.accessKey {
|
||||
text-decoration : underline;
|
||||
}
|
||||
|
||||
|
||||
#globalOperationsPanel .header{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#globalOperationsPanel .control {
|
||||
height : 24px;
|
||||
width : 98px;
|
||||
background: url('images/console_button_lg.png') 0 0;
|
||||
}
|
||||
|
||||
#globalOperationsPanel .control:hover {
|
||||
background: url('images/console_button_lg.png') 204px 0;
|
||||
}
|
||||
|
||||
#globalOperationsPanel .control:active {
|
||||
background: url('images/console_button_lg.png') 102px 0;
|
||||
}
|
||||
206
installer/resources/themes/console/defCon1/i2ptunnel.css
Normal file
@@ -0,0 +1,206 @@
|
||||
/* I2P Tunnel Edit Page
|
||||
*/
|
||||
|
||||
#tunnelEditPage input {
|
||||
width : 458px;
|
||||
}
|
||||
|
||||
#tunnelEditPage select {
|
||||
width : 308px;
|
||||
}
|
||||
|
||||
#tunnelEditPage option[selected] {
|
||||
color: green;
|
||||
}
|
||||
|
||||
#tunnelEditPage #targetField,
|
||||
#tunnelEditPage #accessField,
|
||||
#tunnelEditPage #optionsField {
|
||||
height : 48px;
|
||||
width : 150px;
|
||||
}
|
||||
#tunnelEditPage #tunnelOptionsField {
|
||||
height : 96px;
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #targetField label,
|
||||
#tunnelEditPage #accessField label,
|
||||
#tunnelEditPage #tunnelOptionsField label,
|
||||
#tunnelEditPage #optionsField label{
|
||||
height : 48px;
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#tunnelEditPage #reachField,
|
||||
#tunnelEditPage #hostField,
|
||||
#tunnelEditPage #depthField,
|
||||
#tunnelEditPage #countField,
|
||||
#tunnelEditPage #optionsHostField {
|
||||
width : 304px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #portField,
|
||||
#tunnelEditPage #optionsPortField,
|
||||
#tunnelEditPage #backupField,
|
||||
#tunnelEditPage #varianceField {
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #reachField label,
|
||||
#tunnelEditPage #hostField label,
|
||||
#tunnelEditPage #portField label,
|
||||
#tunnelEditPage #optionsHostField label,
|
||||
#tunnelEditPage #optionsPortField label,
|
||||
#tunnelEditPage #depthField label,
|
||||
#tunnelEditPage #countField label,
|
||||
#tunnelEditPage #backupField label,
|
||||
#tunnelEditPage #varianceField label {
|
||||
text-align : left;
|
||||
padding : 2px 0 0 4px;
|
||||
background: url('images/aqua_column_title_vert.png') 0 0 no-repeat;
|
||||
}
|
||||
|
||||
#tunnelEditPage #otherField label {
|
||||
width : 300px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #reachableByOther,
|
||||
#tunnelEditPage #tunnelDepth,
|
||||
#tunnelEditPage #tunnelQuantity,
|
||||
#tunnelEditPage #targetHost,
|
||||
#tunnelEditPage #clientHost {
|
||||
width : 306px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #port {
|
||||
width : 80px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #targetPort,
|
||||
#tunnelEditPage #clientPort,
|
||||
#tunnelEditPage #tunnelBackupQuantity,
|
||||
#tunnelEditPage #tunnelVariance {
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
#tunnelEditPage #shared,
|
||||
#tunnelEditPage #connectDelay,
|
||||
#tunnelEditPage #startOnLoad {
|
||||
width : 16px;
|
||||
margin : 4px 0 0 4px;
|
||||
}
|
||||
|
||||
#tunnelEditPage label {
|
||||
width : 150px;
|
||||
font-weight : bold;
|
||||
text-align : right;
|
||||
float : left;
|
||||
background: url('images/aqua_column_title_horz.png') 0 0 no-repeat;
|
||||
padding : 2px 4px 0 0;
|
||||
}
|
||||
|
||||
#tunnelEditPage #otherField label {
|
||||
background: url('images/aqua_column_title_horz.png') 150px 0 no-repeat;
|
||||
}
|
||||
|
||||
/* I2P Tunnel List Page
|
||||
*/
|
||||
|
||||
#tunnelListPage #statusMessagePanel .header,
|
||||
#tunnelEditPage #tunnelEditPanel .header {
|
||||
height: 40px;
|
||||
background: url('images/aqua_titlebar.png') no-repeat;
|
||||
|
||||
}
|
||||
|
||||
#tunnelListPage .rowItem {
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
#tunnelListPage select {
|
||||
width : 150px;
|
||||
}
|
||||
|
||||
#tunnelListPage textarea {
|
||||
width : 760px;
|
||||
height : 100px;
|
||||
padding : 0 0 0 4px;
|
||||
}
|
||||
|
||||
#tunnelListPage .footer .control {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
#tunnelListPage .footer label {
|
||||
text-align : right;
|
||||
height : 24px;
|
||||
width : 160px;
|
||||
float : left;
|
||||
|
||||
}
|
||||
|
||||
/* Use Leary and Langridge content replacement methods (LIR)
|
||||
** to embed accessibility information into the document.
|
||||
** Should allow the lists to be rendered nicely by
|
||||
** screen readers. (and lynx!)
|
||||
*/
|
||||
|
||||
#tunnelListPage label {
|
||||
height : 0;
|
||||
width : 0;
|
||||
overflow : hidden;
|
||||
}
|
||||
|
||||
#tunnelListPage .nameHeaderField label,
|
||||
#tunnelListPage .portHeaderField label,
|
||||
#tunnelListPage .typeHeaderField label,
|
||||
#tunnelListPage .interfaceHeaderField label,
|
||||
#tunnelListPage .targetHeaderField label,
|
||||
#tunnelListPage .previewHeaderField label,
|
||||
#tunnelListPage .statusHeaderField label {
|
||||
text-align : left;
|
||||
width : 150px;
|
||||
height : 24px;
|
||||
float : left;
|
||||
padding : 2px 0 0 4px;
|
||||
background: url('images/aqua_column_title_vert.png') 0 0 no-repeat;
|
||||
}
|
||||
|
||||
#tunnelListPage .nameField .text {
|
||||
padding: 2px 0 0 8px;
|
||||
}
|
||||
|
||||
#tunnelListPage .targetField,
|
||||
#tunnelListPage .targetField .text,
|
||||
#tunnelListPage .targetHeaderField,
|
||||
#tunnelListPage .targetHeaderField label {
|
||||
width : 300px;
|
||||
}
|
||||
|
||||
#tunnelListPage .descriptionField,
|
||||
#tunnelListPage .destinationField {
|
||||
width : 750px;
|
||||
}
|
||||
|
||||
#tunnelListPage .descriptionField .text,
|
||||
#tunnelListPage .destinationField input {
|
||||
width : 450px;
|
||||
}
|
||||
|
||||
#tunnelListPage .descriptionField label,
|
||||
#tunnelListPage .destinationField label {
|
||||
text-align : right;
|
||||
width : 150px;
|
||||
height : 24px;
|
||||
float : left;
|
||||
background: url('images/aqua_column_title_horz.png') 0 0 no-repeat;
|
||||
padding : 2px 4px 0 0;
|
||||
}
|
||||
|
||||
#tunnelListPage .statusField .control {
|
||||
margin : 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 758 B |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 706 B |
|
After Width: | Height: | Size: 817 B |
|
After Width: | Height: | Size: 249 B |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |