Compare commits

..

48 Commits

Author SHA1 Message Date
jrandom
f7236d7d58 * 2005-11-15 0.6.1.5 released 2005-11-16 03:20:20 +00:00
jrandom
5182008b38 more stuff 2005-11-16 03:12:04 +00:00
jrandom
9d030327e6 put rome and jdom in the syndie.war, and fix some deprecation warnings 2005-11-15 12:46:54 +00:00
jrandom
a15c90d2cc add in a basic limit on the attachment size (trivially circumvented, but for now it'll do)
fixed some links
2005-11-15 11:17:04 +00:00
jrandom
84c2a713e1 update the post 2005-11-15 10:23:29 +00:00
jrandom
7db9ce6e5b update the default syndie post, and add in some html hooks for it
only allow 40 chars in the subject within the thread tree
2005-11-15 10:22:57 +00:00
jrandom
da42f5717b logging cleanup 2005-11-15 06:38:00 +00:00
jrandom
5241953e5d logging 2005-11-15 06:37:20 +00:00
jrandom
b1a5f61ba2 cleanup and logging 2005-11-15 06:34:04 +00:00
jrandom
024a5a1ad4 deal with spaces in filenames cleanly 2005-11-15 06:29:51 +00:00
jrandom
b031de5404 more cleanup 2005-11-15 06:24:17 +00:00
jrandom
dceac73951 2005-11-14 jrandom
* Migrate to the new Syndie interface
2005-11-15 00:45:36 +00:00
jrandom
8f95143488 more syndie cleanup 2005-11-15 00:24:35 +00:00
jrandom
a8f3043aae * move over the rssimport, and default it to the proxy @ localhost:4444 2005-11-14 05:40:18 +00:00
jrandom
6c91b2d4a9 migrate to the new system 2005-11-14 02:09:23 +00:00
jrandom
ddd438de35 protect against spoofing in syndie with a per-jvm-instance nonce (which should prevent the spurious "are you being spoofed" things)
fixed the syndie previewing
2005-11-13 14:15:26 +00:00
jrandom
16fd46db2b move the admin page over to the new system 2005-11-13 11:04:17 +00:00
jrandom
1159c155a4 * migrate the post/preview over to the new system
* honor the "force new thread" and "refuse replies (from everyone but me)" functionality
2005-11-13 07:55:38 +00:00
jrandom
30b4e2aa2a change one's password 2005-11-13 04:47:15 +00:00
jrandom
ae46fa2e6d allow the user to change their password 2005-11-13 04:46:28 +00:00
jrandom
9fc34895c9 more careful ops 2005-11-13 03:46:20 +00:00
jrandom
08be4c7b3d migrated the syndie addressbook 2005-11-13 03:42:52 +00:00
dust
7443457af4 * Ignore <ul>. Add <strong>, <p> and <li>.
* change to make [ and ] use their &#n;.
2005-11-12 17:10:56 +00:00
jrandom
979a4cfb69 migrate the switchuser and register 2005-11-12 13:01:32 +00:00
jrandom
ed285871bf migrate the profile page to the new format, and refactor the new format's servlets 2005-11-12 12:14:23 +00:00
jrandom
8c70b8b32a ircclient too :) 2005-11-12 05:06:57 +00:00
jrandom
14134694d7 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-12 05:03:51 +00:00
cervantes
807d2d3509 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-12 02:52:40 +00:00
cervantes
b222cd43f4 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-12 02:38:55 +00:00
jrandom
7f6aa327f2 allow the user to override what login/pass is used for the default user in single user mode 2005-11-11 12:26:17 +00:00
jrandom
49564a3878 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-11 11:29:15 +00:00
jrandom
12ddaff0ce .. 2005-11-11 10:09:04 +00:00
jrandom
a8ea239dcc *cough* 2005-11-11 09:58:03 +00:00
jrandom
ca391097a9 onwards, christian soldiers 2005-11-11 09:39:48 +00:00
jrandom
4297edc88f wait until we build the tree before sorting the threads, so we can have the most recently updated thread first 2005-11-11 05:10:38 +00:00
jrandom
6de4673e9e 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-11 03:46:36 +00:00
jrandom
f6979c811f 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-11 03:41:16 +00:00
jrandom
bd86483204 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-06 22:25:17 +00:00
jrandom
53cf03cec6 no need for ant's IgnoreBlank (and its not in the classpath anyway) 2005-11-05 22:50:14 +00:00
jrandom
e284a8878b 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 21:19:05 +00:00
jrandom
14cd469c6d 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 21:12:57 +00:00
dust
9050d7c218 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-05 11:01:57 +00:00
jrandom
0ad18cd0ba 2005-10-31 jrandom
* Fix for some syndie reply scenarios (thanks identiguy and CofE!)
    * Removed a potentially infinitely recursive call (oops)
(forgot to commit this file before.  oops)
2005-11-04 03:08:00 +00:00
jrandom
ca0af146b7 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-04 01:20:17 +00:00
jrandom
a2d2b031f4 2005-11-01 jrandom
* Added a few more css elements (thanks identiguy!)
2005-11-02 00:35:21 +00:00
jrandom
2f36912ac0 2005-10-31 jrandom
* Fix for some syndie reply scenarios (thanks identiguy and CofE!)
    * Removed a potentially infinitely recursive call (oops)
2005-10-31 20:03:11 +00:00
dust
53e32c8e64 *** empty log message *** 2005-10-30 07:38:42 +00:00
dust
10dde610dc 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("<","&lt;") for logs.
2005-10-30 05:47:55 +00:00
121 changed files with 7122 additions and 1819 deletions

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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");
}
}
}
}

View File

@@ -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<%
}
}
%>

View File

@@ -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>
&nbsp;&nbsp;
<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>
&nbsp;&nbsp;
<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>
&nbsp;&nbsp;
<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" /> &nbsp;&nbsp;
<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>

View File

@@ -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" /> &nbsp;&nbsp;
<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>

View File

@@ -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()%>&amp;action=stop&amp;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()%>&amp;action=stop&amp;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()%>&amp;action=start&amp;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()%>&amp;action=stop&amp;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()%>&amp;action=stop&amp;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()%>&amp;action=start&amp;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()%>&amp;action=Stop%20all">Stop All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=Start%20all">Start All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=Restart%20all">Restart All</a><a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=Reload%20configuration">Reload Config</a>
</div>
</div>
</div>
<div id="pageFooter">
</div>
</body>
</html>

View File

@@ -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("<","&lt;");
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("<","&lt;");
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("<","&lt;");
return "<pre>" + str + "</pre>";
}
}
public String getConnectionLogs() {

View File

@@ -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> |

View 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());
%>

View File

@@ -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

View File

@@ -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/" />

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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) ) {

View 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) {}
}

View File

@@ -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+="&lt;";
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+="&lt;";
break;
case '\r':
if(!stripNewlines)
sml+='\r';
break;
case '\n':
if(!stripNewlines)
sml+='\n';
break;
case '[':
sml+="&#91;";
break;
case ']':
sml+="&#93;";
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("\\[","&#91;").replaceAll("\\]","&#93;");
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("&amp;","&");
String attachmentPath = messagePath+"."+attachmentCounter;
link=link.replaceAll("&amp;","&");
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();
}
}

View 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(); }
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);

View 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;
}
}
}
}

View File

@@ -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 + "";

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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; }
}

View 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); }
}

View 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();
}

View File

@@ -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(); }

View File

@@ -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>");
}
}

View File

@@ -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 &lt;
//str = str.replace('>', '-'); // this should be &gt;
str = str.replaceAll("<", "&lt;");
str = str.replaceAll(">", "&gt;");
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 &lt;
//str = str.replace('>', '-'); // this should be &gt;
str = str.replaceAll("<", "&lt;");
str = str.replaceAll(">", "&gt;");
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);
}
}

View File

@@ -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");
}

View File

@@ -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();

View File

@@ -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();
}
}

View 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"; }
}

View 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"; }
}

View File

@@ -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);

View File

@@ -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 + "\">&lt;&lt;</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 + "\">&gt;&gt;</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>");

View 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; }
}
}

View File

@@ -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);

View File

@@ -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");
}
}
}
}

View 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\">&nbsp;</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");
}
}
}

View File

@@ -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();
}

View 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"; }
}

View 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";
}

View File

@@ -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));
}
}

View File

@@ -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");

View 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");
}
}

View 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;
}
}

View 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("&lt;&lt; First Page ");
} else {
out.write("<a href=\"");
out.write(getNavLink(req, 0));
out.write("\">&lt;&lt; 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("\">&lt; Prev Page</a>\n");
} else {
out.write("&lt; Prev Page\n");
}
out.write("</td><td class=\"threadNavRight\" nowrap=\"true\">\n");
int max = index.getRootCount();
if (threadOffset + 10 > max) {
out.write("Next Page&gt; Last Page&gt;&gt;\n");
} else {
out.write("<a href=\"");
out.write(getNavLink(req, threadOffset + 10));
out.write("\">Next Page&gt;</a> <a href=\"");
out.write(getNavLink(req, -1));
out.write("\">Last Page&gt;&gt;</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 "&nbsp;";
}
protected String getTitle() { return "Syndie :: View threads"; }
}

View File

@@ -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 {%>

View 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>

View File

@@ -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">&nbsp;</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>

View File

@@ -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>

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

View 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>

View File

@@ -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>

View File

@@ -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 &lt; and &gt; are replaced with their &amp;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>

View File

@@ -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>

View 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 &lt; and &gt; are replaced with their &amp;symbol;</li>
<li>[b][/b] = &lt;b&gt;bold&lt;/b&gt;</li>
<li>[i][/i] = &lt;i&gt;italics&lt;/i&gt;</li>
<li>[u][/u] = &lt;i&gt;underline&lt;/i&gt;</li>
<li>[cut]more inside[/cut] = &lt;a href="#"&gt;more inside...&lt;/a&gt;</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>

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -25,6 +25,6 @@ public class BrowserChooser extends FileDialog {
}
public void initialize(){
this.show();
this.setVisible(true);
}
}

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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("<","&lt;") for logs.
* 2005-10-29 0.6.1.4 released

View File

@@ -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

View File

@@ -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"

View File

@@ -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>

Binary file not shown.

View 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>

View 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;
}

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Some files were not shown because too many files have changed in this diff Show More