Compare commits
90 Commits
i2p_0_6_0_
...
i2p_0_6_1_
Author | SHA1 | Date | |
---|---|---|---|
6019a03029 | |||
df5736f571 | |||
9a73c6defe | |||
9dfa87ba47 | |||
934a269753 | |||
1c0dfc242b | |||
3bc3e5d47e | |||
55869af2cc | |||
9f336dd05b | |||
411ca5e6c3 | |||
c528e4db03 | |||
848ead7683 | |||
1b8419b9b5 | |||
900420719e | |||
ef7d1ba964 | |||
ab1654c784 | |||
24bad8e4bb | |||
f6d8200bc8 | |||
aef33548b3 | |||
56ecdcce82 | |||
b9b59ff95f | |||
aa9dd3e5c6 | |||
30bd659149 | |||
3286ca49c8 | |||
7700d12178 | |||
557b7e3f2e | |||
3e1e9146e1 | |||
40d8d1aac1 | |||
1457b8efba | |||
3821e80ac8 | |||
d40bb459ea | |||
edf04f07c9 | |||
2bdea23986 | |||
6be0c4b694 | |||
2a272f465c | |||
a8ecd32b45 | |||
20c42a175d | |||
d6c3ffde87 | |||
177e0ae6a3 | |||
dab1b4d256 | |||
3aba12631b | |||
cfee6430d4 | |||
6b96df1cec | |||
deecfa5047 | |||
6ca3f01038 | |||
d89f589f2b | |||
8c1895e04f | |||
c3d0132a98 | |||
d955279d17 | |||
76266dce0d | |||
5694206b35 | |||
4293a18726 | |||
9865af4174 | |||
c8c109093d | |||
b5784d6025 | |||
31bdb8909a | |||
ee921c22ae | |||
172ffd0434 | |||
d9b4406c09 | |||
8ac0e85df4 | |||
249ccd5e3c | |||
727d76d43e | |||
44770b7c07 | |||
b5d571c75f | |||
da56d83716 | |||
f777e213ce | |||
79906f5a7d | |||
54074e76b5 | |||
c2ea8db683 | |||
744671a518 | |||
7f5b127bbc | |||
89eff0c628 | |||
177aeebb1c | |||
e0e6bde4a5 | |||
e6b145716f | |||
f958342704 | |||
5a1f738505 | |||
8147cdf40c | |||
6afc64ac39 | |||
61b8e3598b | |||
3bb445ff40 | |||
59a8037599 | |||
09cb5fad59 | |||
ee8e45ecf7 | |||
339868838d | |||
c5579fa349 | |||
d4a859547c | |||
779aa240d2 | |||
9aaad00383 | |||
6422f7ef78 |
@ -36,6 +36,7 @@ import java.io.File;
|
||||
*/
|
||||
public class Daemon {
|
||||
public static final String VERSION = "2.0.3";
|
||||
private static final Daemon _instance = new Daemon();
|
||||
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
@ -56,7 +57,7 @@ public class Daemon {
|
||||
* @param log
|
||||
* The log to write changes and conflicts to.
|
||||
*/
|
||||
public static void update(AddressBook master, AddressBook router,
|
||||
public void update(AddressBook master, AddressBook router,
|
||||
File published, SubscriptionList subscriptions, Log log) {
|
||||
router.merge(master, true, null);
|
||||
Iterator iter = subscriptions.iterator();
|
||||
@ -77,7 +78,7 @@ public class Daemon {
|
||||
* @param home
|
||||
* The directory containing addressbook's configuration files.
|
||||
*/
|
||||
public static void update(Map settings, String home) {
|
||||
public void update(Map settings, String home) {
|
||||
File masterFile = new File(home, (String) settings
|
||||
.get("master_addressbook"));
|
||||
File routerFile = new File(home, (String) settings
|
||||
@ -104,7 +105,7 @@ public class Daemon {
|
||||
.get("proxy_host"), Integer.parseInt((String) settings.get("proxy_port")));
|
||||
Log log = new Log(logFile);
|
||||
|
||||
Daemon.update(master, router, published, subscriptions, log);
|
||||
update(master, router, published, subscriptions, log);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,6 +119,10 @@ public class Daemon {
|
||||
* others are ignored.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
_instance.run(args);
|
||||
}
|
||||
|
||||
public void run(String[] args) {
|
||||
String settingsLocation = "config.txt";
|
||||
Map settings = new HashMap();
|
||||
String home;
|
||||
@ -151,19 +156,36 @@ public class Daemon {
|
||||
|
||||
File settingsFile = new File(homeFile, settingsLocation);
|
||||
|
||||
settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
// wait
|
||||
try {
|
||||
Thread.currentThread().sleep(5*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
while (true) {
|
||||
settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
|
||||
long delay = Long.parseLong((String) settings.get("update_delay"));
|
||||
if (delay < 1) {
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
Daemon.update(settings, home);
|
||||
update(settings, home);
|
||||
try {
|
||||
Thread.sleep(delay * 60 * 60 * 1000);
|
||||
synchronized (this) {
|
||||
wait(delay * 60 * 60 * 1000);
|
||||
}
|
||||
} catch (InterruptedException exp) {
|
||||
}
|
||||
settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to get the addressbook to reread its config and
|
||||
* refetch its subscriptions.
|
||||
*/
|
||||
public static void wakeup() {
|
||||
synchronized (_instance) {
|
||||
_instance.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
@ -44,10 +44,10 @@ public class DaemonThread extends Thread {
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5 * 60 * 1000);
|
||||
} catch (InterruptedException exp) {
|
||||
}
|
||||
//try {
|
||||
// Thread.sleep(5 * 60 * 1000);
|
||||
//} catch (InterruptedException exp) {
|
||||
//}
|
||||
Daemon.main(this.args);
|
||||
}
|
||||
}
|
@ -8,36 +8,50 @@ package net.i2p.i2ptunnel;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Simple stream for delivering an HTTP response to
|
||||
* the client, trivially filtered to make sure "Connection: close"
|
||||
* is always in the response.
|
||||
* is always in the response. Perhaps add transparent handling of the
|
||||
* Content-encoding: x-i2p-gzip, adjusting the headers to say Content-encoding: identity?
|
||||
* Content-encoding: gzip is trivial as well, but Transfer-encoding: chunked makes it
|
||||
* more work than is worthwhile at the moment.
|
||||
*
|
||||
*/
|
||||
class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
private static final Log _log = new Log(HTTPResponseOutputStream.class);
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private ByteCache _cache;
|
||||
protected ByteArray _headerBuffer;
|
||||
private boolean _headerWritten;
|
||||
private byte _buf1[];
|
||||
protected boolean _gzip;
|
||||
private long _dataWritten;
|
||||
private InternalGZIPInputStream _in;
|
||||
private static final int CACHE_SIZE = 8*1024;
|
||||
|
||||
public HTTPResponseOutputStream(OutputStream raw) {
|
||||
super(raw);
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
|
||||
_log = _context.logManager().getLog(getClass());
|
||||
_cache = ByteCache.getInstance(8, CACHE_SIZE);
|
||||
_headerBuffer = _cache.acquire();
|
||||
_headerWritten = false;
|
||||
_gzip = false;
|
||||
_dataWritten = 0;
|
||||
_buf1 = new byte[1];
|
||||
}
|
||||
|
||||
@ -51,6 +65,8 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
public void write(byte buf[], int off, int len) throws IOException {
|
||||
if (_headerWritten) {
|
||||
out.write(buf, off, len);
|
||||
_dataWritten += len;
|
||||
out.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -62,8 +78,12 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
if (headerReceived()) {
|
||||
writeHeader();
|
||||
_headerWritten = true;
|
||||
if (i + 1 < len) // write out the remaining
|
||||
if (i + 1 < len) {
|
||||
// write out the remaining
|
||||
out.write(buf, off+i+1, len-i-1);
|
||||
_dataWritten += len-i-1;
|
||||
out.flush();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -128,7 +148,10 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
if ( (keyLen <= 0) || (valLen <= 0) )
|
||||
throw new IOException("Invalid header @ " + j);
|
||||
String key = new String(_headerBuffer.getData(), lastEnd+1, keyLen);
|
||||
String val = new String(_headerBuffer.getData(), j+2, valLen);
|
||||
String val = new String(_headerBuffer.getData(), j+2, valLen).trim();
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Response header [" + key + "] = [" + val + "]");
|
||||
|
||||
if ("Connection".equalsIgnoreCase(key)) {
|
||||
out.write("Connection: close\n".getBytes());
|
||||
@ -136,6 +159,8 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
} else if ("Proxy-Connection".equalsIgnoreCase(key)) {
|
||||
out.write("Proxy-Connection: close\n".getBytes());
|
||||
proxyConnectionSent = true;
|
||||
} else if ( ("Content-encoding".equalsIgnoreCase(key)) && ("x-i2p-gzip".equalsIgnoreCase(val)) ) {
|
||||
_gzip = true;
|
||||
} else {
|
||||
out.write((key.trim() + ": " + val.trim() + "\n").getBytes());
|
||||
}
|
||||
@ -152,13 +177,103 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
if (!proxyConnectionSent)
|
||||
out.write("Proxy-Connection: close\n".getBytes());
|
||||
|
||||
out.write("\n".getBytes()); // end of the headers
|
||||
finishHeaders();
|
||||
|
||||
boolean shouldCompress = shouldCompress();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("After headers: gzip? " + _gzip + " compress? " + shouldCompress);
|
||||
|
||||
// done, shove off
|
||||
if (_headerBuffer.getData().length == CACHE_SIZE)
|
||||
_cache.release(_headerBuffer);
|
||||
else
|
||||
_headerBuffer = null;
|
||||
if (shouldCompress) {
|
||||
beginProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldCompress() { return _gzip; }
|
||||
|
||||
protected void finishHeaders() throws IOException {
|
||||
out.write("\n".getBytes()); // end of the headers
|
||||
}
|
||||
|
||||
protected void beginProcessing() throws IOException {
|
||||
//out.flush();
|
||||
PipedInputStream pi = new PipedInputStream();
|
||||
PipedOutputStream po = new PipedOutputStream(pi);
|
||||
new I2PThread(new Pusher(pi, out), "HTTP decompresser").start();
|
||||
out = po;
|
||||
}
|
||||
|
||||
private class Pusher implements Runnable {
|
||||
private InputStream _inRaw;
|
||||
private OutputStream _out;
|
||||
public Pusher(InputStream in, OutputStream out) {
|
||||
_inRaw = in;
|
||||
_out = out;
|
||||
}
|
||||
public void run() {
|
||||
OutputStream to = null;
|
||||
_in = null;
|
||||
long start = System.currentTimeMillis();
|
||||
long written = 0;
|
||||
try {
|
||||
_in = new InternalGZIPInputStream(_inRaw);
|
||||
byte buf[] = new byte[8192];
|
||||
int read = -1;
|
||||
while ( (read = _in.read(buf)) != -1) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read " + read + " and writing it to the browser/streams");
|
||||
_out.write(buf, 0, read);
|
||||
_out.flush();
|
||||
written += read;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Decompressed: " + written + ", " + _in.getTotalRead() + "/" + _in.getTotalExpanded());
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error decompressing: " + written + ", " + (_in != null ? _in.getTotalRead() + "/" + _in.getTotalExpanded() : ""), ioe);
|
||||
} finally {
|
||||
if (_log.shouldLog(Log.WARN) && (_in != null))
|
||||
_log.warn("After decompression, written=" + written +
|
||||
(_in != null ?
|
||||
" read=" + _in.getTotalRead()
|
||||
+ ", expanded=" + _in.getTotalExpanded() + ", remaining=" + _in.getRemaining()
|
||||
+ ", finished=" + _in.getFinished()
|
||||
: ""));
|
||||
if (_out != null) try {
|
||||
_out.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
double compressed = (_in != null ? _in.getTotalRead() : 0);
|
||||
double expanded = (_in != null ? _in.getTotalExpanded() : 0);
|
||||
double ratio = 0;
|
||||
if (expanded > 0)
|
||||
ratio = compressed/expanded;
|
||||
|
||||
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), end-start);
|
||||
_context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed, end-start);
|
||||
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, end-start);
|
||||
}
|
||||
}
|
||||
private class InternalGZIPInputStream extends GZIPInputStream {
|
||||
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 String toString() {
|
||||
return "Read: " + getTotalRead() + " expanded: " + getTotalExpanded() + " remaining: " + getRemaining() + " finished: " + getFinished();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + ": " + _in;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
|
@ -96,6 +96,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel")
|
||||
.getBytes();
|
||||
|
||||
private final static byte[] ERR_AHELPER_CONFLICT =
|
||||
("HTTP/1.1 409 Conflict\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
"<html><body><H1>I2P ERROR: Destination key conflict</H1>"+
|
||||
"The addresshelper link you followed specifies a different destination key "+
|
||||
"than a host entry in your host database. "+
|
||||
"Someone could be trying to impersonate another eepsite, "+
|
||||
"or people have given two eepsites identical names.<P/>"+
|
||||
"You can resolve the conflict by considering which key you trust, "+
|
||||
"and either discarding the addresshelper link, "+
|
||||
"discarding the host entry from your host database, "+
|
||||
"or naming one of them differently.<P/>")
|
||||
.getBytes();
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
@ -179,6 +195,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
return opts;
|
||||
}
|
||||
|
||||
private static final boolean DEFAULT_GZIP = true;
|
||||
|
||||
private static long __requestId = 0;
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
OutputStream out = null;
|
||||
@ -243,50 +261,102 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
// Quick hack for foo.bar.i2p
|
||||
if (host.toLowerCase().endsWith(".i2p")) {
|
||||
// Destination gets the host name
|
||||
destination = host;
|
||||
// Host becomes the destination key
|
||||
host = getHostName(destination);
|
||||
if ( (host != null) && ("i2p".equals(host)) ) {
|
||||
int pos2;
|
||||
if ((pos2 = request.indexOf("?")) != -1) {
|
||||
// Try to find an address helper in the fragments
|
||||
// and split the request into it's component parts for rebuilding later
|
||||
String fragments = request.substring(pos2 + 1);
|
||||
String uriPath = request.substring(0, pos2);
|
||||
pos2 = fragments.indexOf(" ");
|
||||
String protocolVersion = fragments.substring(pos2 + 1);
|
||||
String urlEncoding = "";
|
||||
fragments = fragments.substring(0, pos2);
|
||||
fragments = fragments + "&";
|
||||
String fragment;
|
||||
while(fragments.length() > 0) {
|
||||
pos2 = fragments.indexOf("&");
|
||||
fragment = fragments.substring(0, pos2);
|
||||
fragments = fragments.substring(pos2 + 1);
|
||||
if (fragment.startsWith("i2paddresshelper")) {
|
||||
pos2 = fragment.indexOf("=");
|
||||
if (pos2 >= 0) {
|
||||
addressHelpers.put(destination,fragment.substring(pos2 + 1));
|
||||
}
|
||||
} else {
|
||||
// append each fragment unless it's the address helper
|
||||
if ("".equals(urlEncoding)) {
|
||||
urlEncoding = "?" + fragment;
|
||||
} else {
|
||||
urlEncoding = urlEncoding + "&" + fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reconstruct the request minus the i2paddresshelper GET var
|
||||
request = uriPath + urlEncoding + " " + protocolVersion;
|
||||
}
|
||||
|
||||
String addressHelper = (String) addressHelpers.get(destination);
|
||||
if (addressHelper != null) {
|
||||
destination = addressHelper;
|
||||
host = getHostName(destination);
|
||||
ahelper = 1;
|
||||
int pos2;
|
||||
if ((pos2 = request.indexOf("?")) != -1) {
|
||||
// Try to find an address helper in the fragments
|
||||
// and split the request into it's component parts for rebuilding later
|
||||
String ahelperKey = null;
|
||||
boolean ahelperConflict = false;
|
||||
|
||||
String fragments = request.substring(pos2 + 1);
|
||||
String uriPath = request.substring(0, pos2);
|
||||
pos2 = fragments.indexOf(" ");
|
||||
String protocolVersion = fragments.substring(pos2 + 1);
|
||||
String urlEncoding = "";
|
||||
fragments = fragments.substring(0, pos2);
|
||||
String initialFragments = fragments;
|
||||
fragments = fragments + "&";
|
||||
String fragment;
|
||||
while(fragments.length() > 0) {
|
||||
pos2 = fragments.indexOf("&");
|
||||
fragment = fragments.substring(0, pos2);
|
||||
fragments = fragments.substring(pos2 + 1);
|
||||
|
||||
// Fragment looks like addresshelper key
|
||||
if (fragment.startsWith("i2paddresshelper=")) {
|
||||
pos2 = fragment.indexOf("=");
|
||||
ahelperKey = fragment.substring(pos2 + 1);
|
||||
|
||||
// Key contains data, lets not ignore it
|
||||
if (ahelperKey != null) {
|
||||
|
||||
// Host resolvable only with addresshelper
|
||||
if ( (host == null) || ("i2p".equals(host)) )
|
||||
{
|
||||
// Cannot check, use addresshelper key
|
||||
addressHelpers.put(destination,ahelperKey);
|
||||
} else {
|
||||
// Host resolvable from database, verify addresshelper key
|
||||
// Silently bypass correct keys, otherwise alert
|
||||
if (!host.equals(ahelperKey))
|
||||
{
|
||||
// Conflict: handle when URL reconstruction done
|
||||
ahelperConflict = true;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + "], trusted key [" + host + "], specified key [" + ahelperKey + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Other fragments, just pass along
|
||||
// Append each fragment to urlEncoding
|
||||
if ("".equals(urlEncoding)) {
|
||||
urlEncoding = "?" + fragment;
|
||||
} else {
|
||||
urlEncoding = urlEncoding + "&" + fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reconstruct the request minus the i2paddresshelper GET var
|
||||
request = uriPath + urlEncoding + " " + protocolVersion;
|
||||
|
||||
// Did addresshelper key conflict?
|
||||
if (ahelperConflict)
|
||||
{
|
||||
String str;
|
||||
byte[] header;
|
||||
str = FileUtil.readTextFile("docs/ahelper-conflict-header.ht", 100, true);
|
||||
if (str != null) header = str.getBytes();
|
||||
else header = ERR_AHELPER_CONFLICT;
|
||||
|
||||
if (out != null) {
|
||||
long alias = I2PAppContext.getGlobalContext().random().nextLong();
|
||||
String trustedURL = protocol + uriPath + urlEncoding;
|
||||
String conflictURL = protocol + alias + ".i2p/?" + initialFragments;
|
||||
out.write(header);
|
||||
out.write(("To visit the destination in your host database, click <a href=\"" + trustedURL + "\">here</a>. To visit the conflicting addresshelper link by temporarily giving it a random alias, click <a href=\"" + conflictURL + "\">here</a>.<P/>").getBytes());
|
||||
out.write("</div><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String addressHelper = (String) addressHelpers.get(destination);
|
||||
if (addressHelper != null) {
|
||||
destination = addressHelper;
|
||||
host = getHostName(destination);
|
||||
ahelper = 1;
|
||||
}
|
||||
|
||||
line = method + " " + request.substring(pos);
|
||||
} else if (host.indexOf(".") != -1) {
|
||||
// The request must be forwarded to a WWW proxy
|
||||
@ -369,6 +439,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
if (line.length() == 0) {
|
||||
|
||||
String ok = getTunnel().getContext().getProperty("i2ptunnel.gzip");
|
||||
boolean gzip = DEFAULT_GZIP;
|
||||
if (ok != null)
|
||||
gzip = Boolean.valueOf(ok).booleanValue();
|
||||
if (gzip)
|
||||
newRequest.append("Accept-Encoding: x-i2p-gzip\r\n");
|
||||
newRequest.append("User-Agent: MYOB/6.66 (AN/ON)\r\n");
|
||||
newRequest.append("Connection: close\r\n\r\n");
|
||||
break;
|
||||
|
@ -3,16 +3,13 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
@ -30,12 +27,38 @@ import net.i2p.util.Log;
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
|
||||
private Log _log;
|
||||
public I2PTunnelHTTPClientRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData, List sockList, Runnable onTimeout) {
|
||||
super(s, i2ps, slock, initialI2PData, sockList, onTimeout);
|
||||
_log = I2PAppContext.getGlobalContext().logManager().getLog(I2PTunnelHTTPClientRunner.class);
|
||||
}
|
||||
|
||||
protected OutputStream getSocketOut() throws IOException {
|
||||
OutputStream raw = super.getSocketOut();
|
||||
return new HTTPResponseOutputStream(raw);
|
||||
}
|
||||
|
||||
protected void close(OutputStream out, InputStream in, OutputStream i2pout, InputStream i2pin, Socket s, I2PSocket i2ps, Thread t1, Thread t2) throws InterruptedException, IOException {
|
||||
try {
|
||||
i2pin.close();
|
||||
i2pout.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Unable to close the i2p socket output stream: " + i2pout, ioe);
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Unable to close the browser output stream: " + out, ioe);
|
||||
}
|
||||
i2ps.close();
|
||||
s.close();
|
||||
t1.join(30*1000);
|
||||
t2.join(30*1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,14 +3,13 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@ -24,7 +23,9 @@ import net.i2p.util.Log;
|
||||
/**
|
||||
* Simple extension to the I2PTunnelServer that filters the HTTP
|
||||
* headers sent from the client to the server, replacing the Host
|
||||
* header with whatever this instance has been configured with.
|
||||
* header with whatever this instance has been configured with, and
|
||||
* if the browser set Accept-encoding: x-i2p-gzip, gzip the http
|
||||
* message body and set Content-encoding: x-i2p-gzip.
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
@ -62,14 +63,46 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
try {
|
||||
// give them 5 seconds to send in the HTTP request
|
||||
socket.setReadTimeout(5*1000);
|
||||
String modifiedHeader = getModifiedHeader(socket);
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
StringBuffer command = new StringBuffer(128);
|
||||
Properties headers = readHeaders(in, command);
|
||||
if ( (_spoofHost != null) && (_spoofHost.trim().length() > 0) )
|
||||
headers.setProperty("Host", _spoofHost);
|
||||
headers.setProperty("Connection", "close");
|
||||
// we keep the enc sent by the browser before clobbering it, since it may have
|
||||
// been x-i2p-gzip
|
||||
String enc = headers.getProperty("Accept-encoding");
|
||||
headers.setProperty("Accept-encoding", "identity;q=1, *;q=0");
|
||||
String modifiedHeader = formatHeaders(headers, command);
|
||||
|
||||
//String modifiedHeader = getModifiedHeader(socket);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Modified header: [" + modifiedHeader + "]");
|
||||
|
||||
socket.setReadTimeout(readTimeout);
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
afterSocket = getTunnel().getContext().clock().now();
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
|
||||
// instead of i2ptunnelrunner, use something that reads the HTTP
|
||||
// request from the socket, modifies the headers, sends the request to the
|
||||
// server, reads the response headers, rewriting to include Content-encoding: x-i2p-gzip
|
||||
// if it was one of the Accept-encoding: values, and gzip the payload
|
||||
Properties opts = getTunnel().getClientOptions();
|
||||
boolean allowGZIP = true;
|
||||
if (opts != null) {
|
||||
String val = opts.getProperty("i2ptunnel.gzip");
|
||||
if ( (val != null) && (!Boolean.valueOf(val).booleanValue()) )
|
||||
allowGZIP = false;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("HTTP server encoding header: " + enc);
|
||||
if ( allowGZIP && (enc != null) && (enc.indexOf("x-i2p-gzip") >= 0) ) {
|
||||
I2PThread req = new I2PThread(new CompressedRequestor(s, socket, modifiedHeader), "http compressor");
|
||||
req.start();
|
||||
} else {
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
|
||||
}
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
@ -88,17 +121,119 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
|
||||
private String getModifiedHeader(I2PSocket handleSocket) throws IOException {
|
||||
InputStream in = handleSocket.getInputStream();
|
||||
|
||||
StringBuffer command = new StringBuffer(128);
|
||||
Properties headers = readHeaders(in, command);
|
||||
headers.setProperty("Host", _spoofHost);
|
||||
headers.setProperty("Connection", "close");
|
||||
return formatHeaders(headers, command);
|
||||
}
|
||||
|
||||
private class CompressedRequestor implements Runnable {
|
||||
private Socket _webserver;
|
||||
private I2PSocket _browser;
|
||||
private String _headers;
|
||||
public CompressedRequestor(Socket webserver, I2PSocket browser, String headers) {
|
||||
_webserver = webserver;
|
||||
_browser = browser;
|
||||
_headers = headers;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Compressed requestor running");
|
||||
OutputStream serverout = null;
|
||||
OutputStream browserout = null;
|
||||
InputStream browserin = null;
|
||||
InputStream serverin = null;
|
||||
try {
|
||||
serverout = _webserver.getOutputStream();
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("request headers: " + _headers);
|
||||
serverout.write(_headers.getBytes());
|
||||
browserin = _browser.getInputStream();
|
||||
I2PThread sender = new I2PThread(new Sender(serverout, browserin, "server: browser to server"), "http compressed sender");
|
||||
sender.start();
|
||||
|
||||
browserout = _browser.getOutputStream();
|
||||
serverin = _webserver.getInputStream();
|
||||
CompressedResponseOutputStream compressedOut = new CompressedResponseOutputStream(browserout);
|
||||
Sender s = new Sender(compressedOut, serverin, "server: server to browser");
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Before pumping the compressed response");
|
||||
s.run(); // same thread
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("After pumping the compressed response: " + compressedOut.getTotalRead() + "/" + compressedOut.getTotalCompressed());
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("error compressing", ioe);
|
||||
} finally {
|
||||
if (browserout != null) try { browserout.close(); } catch (IOException ioe) {}
|
||||
if (serverout != null) try { serverout.close(); } catch (IOException ioe) {}
|
||||
if (browserin != null) try { browserin.close(); } catch (IOException ioe) {}
|
||||
if (serverin != null) try { serverin.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
private class Sender implements Runnable {
|
||||
private OutputStream _out;
|
||||
private InputStream _in;
|
||||
private String _name;
|
||||
public Sender(OutputStream out, InputStream in, String name) {
|
||||
_out = out;
|
||||
_in = in;
|
||||
_name = name;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(_name + ": Begin sending");
|
||||
try {
|
||||
byte buf[] = new byte[16*1024];
|
||||
int read = 0;
|
||||
int total = 0;
|
||||
while ( (read = _in.read(buf)) != -1) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(_name + ": read " + read + " and sending through the stream");
|
||||
_out.write(buf, 0, read);
|
||||
total += read;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(_name + ": Done sending: " + total);
|
||||
_out.flush();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Error sending", ioe);
|
||||
} finally {
|
||||
if (_in != null) try { _in.close(); } catch (IOException ioe) {}
|
||||
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
private class CompressedResponseOutputStream extends HTTPResponseOutputStream {
|
||||
private InternalGZIPOutputStream _gzipOut;
|
||||
public CompressedResponseOutputStream(OutputStream o) {
|
||||
super(o);
|
||||
}
|
||||
|
||||
protected boolean shouldCompress() { return true; }
|
||||
protected void finishHeaders() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Including x-i2p-gzip as the content encoding in the response");
|
||||
out.write("Content-encoding: x-i2p-gzip\n".getBytes());
|
||||
super.finishHeaders();
|
||||
}
|
||||
|
||||
protected void beginProcessing() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Beginning compression processing");
|
||||
out.flush();
|
||||
_gzipOut = new InternalGZIPOutputStream(out);
|
||||
out = _gzipOut;
|
||||
}
|
||||
public long getTotalRead() { return _gzipOut.getTotalRead(); }
|
||||
public long getTotalCompressed() { return _gzipOut.getTotalCompressed(); }
|
||||
}
|
||||
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(); }
|
||||
}
|
||||
|
||||
private String formatHeaders(Properties headers, StringBuffer command) {
|
||||
StringBuffer buf = new StringBuffer(command.length() + headers.size() * 64);
|
||||
buf.append(command.toString()).append('\n');
|
||||
@ -133,6 +268,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
if (split <= 0) throw new IOException("Invalid HTTP header, missing colon [" + buf.toString() + "]");
|
||||
String name = buf.substring(0, split);
|
||||
String value = buf.substring(split+2); // ": "
|
||||
if ("Accept-encoding".equalsIgnoreCase(name))
|
||||
name = "Accept-encoding";
|
||||
headers.setProperty(name, value);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the header [" + name + "] = [" + value + "]");
|
||||
|
@ -153,11 +153,8 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
onTimeout.run();
|
||||
}
|
||||
|
||||
// now one connection is dead - kill the other as well.
|
||||
s.close();
|
||||
i2ps.close();
|
||||
t1.join(30*1000);
|
||||
t2.join(30*1000);
|
||||
// now one connection is dead - kill the other as well, after making sure we flush
|
||||
close(out, in, i2pout, i2pin, s, i2ps, t1, t2);
|
||||
} catch (InterruptedException ex) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Interrupted", ex);
|
||||
@ -188,6 +185,27 @@ public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorL
|
||||
}
|
||||
}
|
||||
|
||||
protected void close(OutputStream out, InputStream in, OutputStream i2pout, InputStream i2pin, Socket s, I2PSocket i2ps, Thread t1, Thread t2) throws InterruptedException, IOException {
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
i2pout.flush();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
in.close();
|
||||
i2pin.close();
|
||||
// ok, yeah, there's a race here in theory, if data comes in after flushing and before
|
||||
// closing, but its better than before...
|
||||
s.close();
|
||||
i2ps.close();
|
||||
t1.join(30*1000);
|
||||
t2.join(30*1000);
|
||||
}
|
||||
|
||||
public void errorOccurred() {
|
||||
synchronized (finishLock) {
|
||||
finished = true;
|
||||
|
@ -479,9 +479,12 @@ public class IndexBean {
|
||||
public void setStartOnLoad(String moo) {
|
||||
_startOnLoad = true;
|
||||
}
|
||||
public void setSharedClient(String moo) {
|
||||
public void setShared(String moo) {
|
||||
_sharedClient=true;
|
||||
}
|
||||
public void setShared(boolean val) {
|
||||
_sharedClient=val;
|
||||
}
|
||||
public void setConnectDelay(String moo) {
|
||||
_connectDelay = true;
|
||||
}
|
||||
|
@ -166,9 +166,9 @@ if (curTunnel >= 0) {
|
||||
</td>
|
||||
<td>
|
||||
<% if (editBean.isSharedClient(curTunnel)) { %>
|
||||
<input type="checkbox" value="true" name="sharedClient" checked="true" />
|
||||
<input type="checkbox" value="true" name="shared" checked="true" />
|
||||
<% } else { %>
|
||||
<input type="checkbox" value="true" name="sharedClient" />
|
||||
<input type="checkbox" value="true" name="shared" />
|
||||
<% } %>
|
||||
<i>(Share tunnels with other clients and httpclients? Change requires restart of client proxy)</i>
|
||||
</td>
|
||||
|
@ -16,6 +16,7 @@ import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.time.Timestamper;
|
||||
import net.i2p.router.transport.udp.UDPTransport;
|
||||
|
||||
/**
|
||||
* Handler to deal with form submissions from the main config form and act
|
||||
@ -29,11 +30,14 @@ public class ConfigNetHandler extends FormHandler {
|
||||
private boolean _saveRequested;
|
||||
private boolean _recheckReachabilityRequested;
|
||||
private boolean _timeSyncEnabled;
|
||||
private boolean _requireIntroductions;
|
||||
private String _tcpPort;
|
||||
private String _udpPort;
|
||||
private String _inboundRate;
|
||||
private String _inboundBurstRate;
|
||||
private String _inboundBurst;
|
||||
private String _outboundRate;
|
||||
private String _outboundBurstRate;
|
||||
private String _outboundBurst;
|
||||
private String _reseedFrom;
|
||||
private String _sharePct;
|
||||
@ -57,6 +61,7 @@ public class ConfigNetHandler extends FormHandler {
|
||||
public void setSave(String moo) { _saveRequested = true; }
|
||||
public void setEnabletimesync(String moo) { _timeSyncEnabled = true; }
|
||||
public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; }
|
||||
public void setRequireIntroductions(String moo) { _requireIntroductions = true; }
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
_hostname = (hostname != null ? hostname.trim() : null);
|
||||
@ -70,12 +75,18 @@ public class ConfigNetHandler extends FormHandler {
|
||||
public void setInboundrate(String rate) {
|
||||
_inboundRate = (rate != null ? rate.trim() : null);
|
||||
}
|
||||
public void setInboundburstrate(String rate) {
|
||||
_inboundBurstRate = (rate != null ? rate.trim() : null);
|
||||
}
|
||||
public void setInboundburstfactor(String factor) {
|
||||
_inboundBurst = (factor != null ? factor.trim() : null);
|
||||
}
|
||||
public void setOutboundrate(String rate) {
|
||||
_outboundRate = (rate != null ? rate.trim() : null);
|
||||
}
|
||||
public void setOutboundburstrate(String rate) {
|
||||
_outboundBurstRate = (rate != null ? rate.trim() : null);
|
||||
}
|
||||
public void setOutboundburstfactor(String factor) {
|
||||
_outboundBurst = (factor != null ? factor.trim() : null);
|
||||
}
|
||||
@ -253,7 +264,14 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (_timeSyncEnabled) {
|
||||
if (_requireIntroductions) {
|
||||
_context.router().setConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS, "true");
|
||||
addFormNotice("Requiring SSU introduers");
|
||||
} else {
|
||||
_context.router().removeConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS);
|
||||
}
|
||||
|
||||
if (true || _timeSyncEnabled) {
|
||||
// Time sync enable, means NOT disabled
|
||||
_context.router().setConfigSetting(Timestamper.PROP_DISABLED, "false");
|
||||
} else {
|
||||
@ -283,14 +301,22 @@ public class ConfigNetHandler extends FormHandler {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_OUTBOUND_KBPS, _outboundRate);
|
||||
updated = true;
|
||||
}
|
||||
if ( (_inboundBurstRate != null) && (_inboundBurstRate.length() > 0) ) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_INBOUND_BURST_KBPS, _inboundBurstRate);
|
||||
updated = true;
|
||||
}
|
||||
if ( (_outboundBurstRate != null) && (_outboundBurstRate.length() > 0) ) {
|
||||
_context.router().setConfigSetting(ConfigNetHelper.PROP_OUTBOUND_BURST_KBPS, _outboundBurstRate);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
String inRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_INBOUND_KBPS);
|
||||
String inBurstRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_INBOUND_BURST_KBPS);
|
||||
|
||||
if (_inboundBurst != null) {
|
||||
int rateKBps = 0;
|
||||
int burstSeconds = 0;
|
||||
try {
|
||||
rateKBps = Integer.parseInt(inRate);
|
||||
rateKBps = Integer.parseInt(inBurstRate);
|
||||
burstSeconds = Integer.parseInt(_inboundBurst);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// ignore
|
||||
@ -302,13 +328,13 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
String outRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_OUTBOUND_KBPS);
|
||||
String outBurstRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_OUTBOUND_BURST_KBPS);
|
||||
|
||||
if (_outboundBurst != null) {
|
||||
int rateKBps = 0;
|
||||
int burstSeconds = 0;
|
||||
try {
|
||||
rateKBps = Integer.parseInt(outRate);
|
||||
rateKBps = Integer.parseInt(outBurstRate);
|
||||
burstSeconds = Integer.parseInt(_outboundBurst);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// ignore
|
||||
|
@ -2,6 +2,10 @@ package net.i2p.router.web;
|
||||
|
||||
import net.i2p.time.Timestamper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.CommSystemFacade;
|
||||
import net.i2p.data.RouterAddress;
|
||||
import net.i2p.router.transport.udp.UDPAddress;
|
||||
import net.i2p.router.transport.udp.UDPTransport;
|
||||
|
||||
public class ConfigNetHelper {
|
||||
private RouterContext _context;
|
||||
@ -43,19 +47,12 @@ public class ConfigNetHelper {
|
||||
return "" + port;
|
||||
}
|
||||
|
||||
public String getUdpPort() {
|
||||
int port = 8887;
|
||||
String val = _context.getProperty(PROP_I2NP_UDP_PORT);
|
||||
if (val == null)
|
||||
val = _context.getProperty(PROP_I2NP_INTERNAL_UDP_PORT);
|
||||
if (val != null) {
|
||||
try {
|
||||
port = Integer.parseInt(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
// ignore, use default from above
|
||||
}
|
||||
}
|
||||
return "" + port;
|
||||
public String getUdpAddress() {
|
||||
RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
|
||||
if (addr == null)
|
||||
return "unknown";
|
||||
UDPAddress ua = new UDPAddress(addr);
|
||||
return ua.toString();
|
||||
}
|
||||
|
||||
public String getEnableTimeSyncChecked() {
|
||||
@ -66,8 +63,29 @@ public class ConfigNetHelper {
|
||||
return " checked ";
|
||||
}
|
||||
|
||||
public String getRequireIntroductionsChecked() {
|
||||
short status = _context.commSystem().getReachabilityStatus();
|
||||
switch (status) {
|
||||
case CommSystemFacade.STATUS_OK:
|
||||
if ("true".equalsIgnoreCase(_context.getProperty(UDPTransport.PROP_FORCE_INTRODUCERS, "false")))
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
case CommSystemFacade.STATUS_DIFFERENT:
|
||||
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
|
||||
return "checked=\"true\"";
|
||||
case CommSystemFacade.STATUS_UNKNOWN:
|
||||
if ("true".equalsIgnoreCase(_context.getProperty(UDPTransport.PROP_FORCE_INTRODUCERS, "false")))
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
default:
|
||||
return "checked=\"true\"";
|
||||
}
|
||||
}
|
||||
|
||||
public static final String PROP_INBOUND_KBPS = "i2np.bandwidth.inboundKBytesPerSecond";
|
||||
public static final String PROP_OUTBOUND_KBPS = "i2np.bandwidth.outboundKBytesPerSecond";
|
||||
public static final String PROP_INBOUND_BURST_KBPS = "i2np.bandwidth.inboundBurstKBytesPerSecond";
|
||||
public static final String PROP_OUTBOUND_BURST_KBPS = "i2np.bandwidth.outboundBurstKBytesPerSecond";
|
||||
public static final String PROP_INBOUND_BURST = "i2np.bandwidth.inboundBurstKBytes";
|
||||
public static final String PROP_OUTBOUND_BURST = "i2np.bandwidth.outboundBurstKBytes";
|
||||
public static final String PROP_SHARE_PERCENTAGE = "router.sharePercentage";
|
||||
@ -78,14 +96,28 @@ public class ConfigNetHelper {
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "-1";
|
||||
return "16";
|
||||
}
|
||||
public String getOutboundRate() {
|
||||
String rate = _context.getProperty(PROP_OUTBOUND_KBPS);
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "-1";
|
||||
return "16";
|
||||
}
|
||||
public String getInboundBurstRate() {
|
||||
String rate = _context.getProperty(PROP_INBOUND_BURST_KBPS);
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "32";
|
||||
}
|
||||
public String getOutboundBurstRate() {
|
||||
String rate = _context.getProperty(PROP_OUTBOUND_BURST_KBPS);
|
||||
if (rate != null)
|
||||
return rate;
|
||||
else
|
||||
return "32";
|
||||
}
|
||||
public String getInboundBurstFactorBox() {
|
||||
String rate = _context.getProperty(PROP_INBOUND_KBPS);
|
||||
|
@ -198,7 +198,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
// ignore
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("News fetched from " + url + " with " + (alreadyTransferred+bytesTransferred));
|
||||
|
||||
@ -224,4 +224,5 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
||||
File temp = new File(TEMP_NEWS_FILE);
|
||||
temp.delete();
|
||||
}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
}
|
||||
|
@ -28,14 +28,19 @@ public class ReseedHandler {
|
||||
if (nonce == null) return;
|
||||
if (nonce.equals(System.getProperty("net.i2p.router.web.ReseedHandler.nonce")) ||
|
||||
nonce.equals(System.getProperty("net.i2p.router.web.ReseedHandler.noncePrev"))) {
|
||||
synchronized (_reseedRunner) {
|
||||
if (_reseedRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "true");
|
||||
I2PThread reseed = new I2PThread(_reseedRunner, "Reseed");
|
||||
reseed.start();
|
||||
}
|
||||
requestReseed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestReseed() {
|
||||
synchronized (_reseedRunner) {
|
||||
if (_reseedRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "true");
|
||||
System.out.println("Reseeding");
|
||||
I2PThread reseed = new I2PThread(_reseedRunner, "Reseed");
|
||||
reseed.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +51,8 @@ public class ReseedHandler {
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
reseed();
|
||||
reseed(false);
|
||||
System.out.println("Reseeding complete");
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
@ -59,7 +65,7 @@ public class ReseedHandler {
|
||||
* save them into this router's netDb dir.
|
||||
*
|
||||
*/
|
||||
private static void reseed() {
|
||||
private static void reseed(boolean echoStatus) {
|
||||
String seedURL = System.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
if ( (seedURL == null) || (seedURL.trim().length() <= 0) )
|
||||
seedURL = DEFAULT_SEED_URL;
|
||||
@ -85,10 +91,16 @@ public class ReseedHandler {
|
||||
try {
|
||||
fetchSeed(seedURL, (String)iter.next());
|
||||
fetched++;
|
||||
if (echoStatus) {
|
||||
System.out.print(".");
|
||||
if (fetched % 60 == 0)
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (echoStatus) System.out.println();
|
||||
} catch (Throwable t) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(ReseedHandler.class).error("Error reseeding", t);
|
||||
}
|
||||
@ -172,7 +184,11 @@ public class ReseedHandler {
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
reseed();
|
||||
//System.out.println("Done reseeding");
|
||||
if ( (args != null) && (args.length == 1) && (!Boolean.valueOf(args[0]).booleanValue()) ) {
|
||||
System.out.println("Not reseeding, as requested");
|
||||
return; // not reseeding on request
|
||||
}
|
||||
System.out.println("Reseeding");
|
||||
reseed(true);
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,24 @@ public class RouterConsoleRunner {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
// we check the i2p installation directory (.) for a flag telling us not to reseed,
|
||||
// but also check the home directory for that flag too, since new users installing i2p
|
||||
// don't have an installation directory that they can put the flag in yet.
|
||||
File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed");
|
||||
File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p");
|
||||
File noReseedFileAlt2 = new File(".i2pnoreseed");
|
||||
File noReseedFileAlt3 = new File("noreseed.i2p");
|
||||
if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) {
|
||||
File netDb = new File("netDb");
|
||||
// sure, some of them could be "my.info" or various leaseSet- files, but chances are,
|
||||
// if someone has those files, they've already been seeded (at least enough to let them
|
||||
// get i2p started - they can reseed later in the web console)
|
||||
String names[] = (netDb.exists() ? netDb.list() : null);
|
||||
if ( (names == null) || (names.length < 15) ) {
|
||||
ReseedHandler.requestReseed();
|
||||
}
|
||||
}
|
||||
|
||||
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
|
||||
I2PThread t = new I2PThread(fetcher, "NewsFetcher");
|
||||
|
@ -95,7 +95,7 @@ public class SummaryHelper {
|
||||
}
|
||||
|
||||
public boolean allowReseed() {
|
||||
return (_context.netDb().getKnownRouters() < 10);
|
||||
return (_context.netDb().getKnownRouters() < 30);
|
||||
}
|
||||
|
||||
public int getAllPeers() { return _context.netDb().getKnownRouters(); }
|
||||
@ -108,7 +108,7 @@ public class SummaryHelper {
|
||||
case CommSystemFacade.STATUS_DIFFERENT:
|
||||
return "ERR-SymmetricNAT";
|
||||
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
|
||||
return "ERR-Reject";
|
||||
return "OK (NAT)";
|
||||
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
|
||||
default:
|
||||
return "Unknown";
|
||||
@ -206,14 +206,12 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
|
||||
RateStat receiveRate = _context.statManager().getRate("bw.recvRate");
|
||||
if (receiveRate == null) return "0.0";
|
||||
Rate rate = receiveRate.getRate(60*1000);
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(bps);
|
||||
double kbps = rate.getAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
/**
|
||||
* How fast we have been sending data over the last minute (pretty printed
|
||||
@ -224,14 +222,12 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("transport.sendMessageSize");
|
||||
RateStat receiveRate = _context.statManager().getRate("bw.sendRate");
|
||||
if (receiveRate == null) return "0.0";
|
||||
Rate rate = receiveRate.getRate(60*1000);
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(bps);
|
||||
double kbps = rate.getAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,14 +239,12 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
|
||||
RateStat receiveRate = _context.statManager().getRate("bw.recvRate");
|
||||
if (receiveRate == null) return "0.0";
|
||||
Rate rate = receiveRate.getRate(5*60*1000);
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(bps);
|
||||
double kbps = rate.getAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,14 +256,12 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("transport.sendMessageSize");
|
||||
RateStat receiveRate = _context.statManager().getRate("bw.sendRate");
|
||||
if (receiveRate == null) return "0.0";
|
||||
Rate rate = receiveRate.getRate(5*60*1000);
|
||||
double bytes = rate.getLastTotalValue();
|
||||
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(bps);
|
||||
double kbps = rate.getAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,20 +273,11 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
long received = _context.bandwidthLimiter().getTotalAllocatedInboundBytes();
|
||||
|
||||
RateStat receiveRate = _context.statManager().getRate("bw.recvRate");
|
||||
if (receiveRate == null) return "0.0";
|
||||
double kbps = receiveRate.getLifetimeAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
|
||||
// we use the unadjusted time, since thats what getWhenStarted is based off
|
||||
long lifetime = _context.clock().now()-_context.clock().getOffset()
|
||||
- _context.router().getWhenStarted();
|
||||
lifetime /= 1000;
|
||||
if (received > 0) {
|
||||
double receivedKBps = received / (lifetime*1024.0);
|
||||
return fmt.format(receivedKBps);
|
||||
} else {
|
||||
return "0.0";
|
||||
}
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,20 +289,11 @@ public class SummaryHelper {
|
||||
if (_context == null)
|
||||
return "0.0";
|
||||
|
||||
long sent = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes();
|
||||
|
||||
RateStat sendRate = _context.statManager().getRate("bw.sendRate");
|
||||
if (sendRate == null) return "0.0";
|
||||
double kbps = sendRate.getLifetimeAverageValue()/1024;
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
|
||||
// we use the unadjusted time, since thats what getWhenStarted is based off
|
||||
long lifetime = _context.clock().now()-_context.clock().getOffset()
|
||||
- _context.router().getWhenStarted();
|
||||
lifetime /= 1000;
|
||||
if (sent > 0) {
|
||||
double sendKBps = sent / (lifetime*1024.0);
|
||||
return fmt.format(sendKBps);
|
||||
} else {
|
||||
return "0.0";
|
||||
}
|
||||
return fmt.format(kbps);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ package net.i2p.router.web;
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
@ -93,7 +94,7 @@ public class UpdateHandler {
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
update();
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.updateInProgress", "false");
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
private void update() {
|
||||
@ -143,7 +144,7 @@ public class UpdateHandler {
|
||||
buf.append(" transferred<br />");
|
||||
_status = buf.toString();
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
_status = "<b>Update downloaded</b><br />";
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
boolean ok = up.migrateVerified(RouterVersion.VERSION, SIGNED_UPDATE_FILE, "i2pupdate.zip");
|
||||
@ -165,6 +166,7 @@ public class UpdateHandler {
|
||||
_status = "<b>Transfer failed</b><br />";
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
|
@ -2,7 +2,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - logs</title>
|
||||
<title>I2P Router Console - config networking</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
|
||||
@ -28,60 +28,38 @@
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" />
|
||||
<input type="hidden" name="action" value="blah" />
|
||||
|
||||
UDP port: <i><jsp:getProperty name="nethelper" property="udpPort" /></i><br />
|
||||
<!-- <input name="udpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="udpPort" />" /><br /> -->
|
||||
<b>You must poke a hole in your firewall or NAT (if applicable) to receive new inbound UDP packets on
|
||||
this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, but is necessary now)</b><br />
|
||||
TCP port: <input name="tcpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="tcpPort" />" /> <br />
|
||||
<b>You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP
|
||||
connections on it (this requirement will be removed in i2p 0.6.1, but is necessary now)</b>
|
||||
<br />
|
||||
<b>External UDP address:</b> <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
|
||||
<b>Require SSU introductions? </b>
|
||||
<input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
|
||||
<p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
|
||||
you on your external UDP address. If you can't, I2P now includes supports UDP hole punching
|
||||
with "SSU introductions" - peers who will relay a request from someone you don't know to your
|
||||
router for your router so that you can make an outbound connection to them. I2P will use these
|
||||
introductions automatically if it detects that the port is not forwarded (as shown by
|
||||
the <i>Status: OK (NAT)</i> line), or you can manually require them here.
|
||||
Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.</p>
|
||||
<input type="submit" name="recheckReachability" value="Check network reachability..." />
|
||||
<hr />
|
||||
|
||||
<b>Bandwidth limiter</b><br />
|
||||
Inbound rate:
|
||||
<input name="inboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundRate" />" /> KBytes per second
|
||||
<input name="inboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundRate" />" /> KBps
|
||||
bursting up to
|
||||
<input name="inboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundBurstRate" />" /> KBps for
|
||||
<jsp:getProperty name="nethelper" property="inboundBurstFactorBox" /><br />
|
||||
Outbound rate:
|
||||
<input name="outboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundRate" />" /> KBytes per second
|
||||
<input name="outboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundRate" />" /> KBps
|
||||
bursting up to
|
||||
<input name="outboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundBurstRate" />" /> KBps for
|
||||
<jsp:getProperty name="nethelper" property="outboundBurstFactorBox" /><br />
|
||||
<i>A negative rate means there is no limit</i><br />
|
||||
<i>KBps = kilobytes per second = 1024 bytes per second.<br />
|
||||
A negative rate means a default limit of 16KBytes per second.</i><br />
|
||||
Bandwidth share percentage:
|
||||
<jsp:getProperty name="nethelper" property="sharePercentageBox" /><br />
|
||||
Sharing a higher percentage will improve your anonymity and help the network
|
||||
<hr />
|
||||
Enable internal time synchronization? <input type="checkbox" <jsp:getProperty name="nethelper" property="enableTimeSyncChecked" /> name="enabletimesync" /><br />
|
||||
<i>If disabled, your machine <b>must</b> be NTP synchronized - your clock must always
|
||||
be within a few seconds of "correct". You will need to be able to send outbound UDP
|
||||
packets on port 123 to one of the pool.ntp.org machines (or some other SNTP server).</i>
|
||||
<hr />
|
||||
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
|
||||
<i>Changing the TCP or UDP port will force a 'soft restart' - dropping your connections and clients as
|
||||
if the router was stopped and restarted. <b>Please be patient</b> - it may take
|
||||
a few seconds to complete.</i>
|
||||
</form>
|
||||
<hr />
|
||||
<b>Advanced network config:</b>
|
||||
<p>
|
||||
One advanced network option has to do with reseeding - you should never need to
|
||||
reseed your router as long as you can find at least one other peer on the network. However,
|
||||
when you do need to reseed, a link will show up on the left hand side which will
|
||||
fetch all of the routerInfo-* files from http://dev.i2p.net/i2pdb/. That URL is just an
|
||||
apache folder pointing at the netDb/ directory of a router - anyone can run one, and you can
|
||||
configure your router to seed off an alternate URL by adding the java environmental property
|
||||
"i2p.reseedURL=someURL" (e.g. java -Di2p.reseedURL=http://dev.i2p.net/i2pdb/ ...). You can
|
||||
also do it manually by getting routerInfo-*.dat files from someone (a friend, someone on IRC,
|
||||
whatever) and saving them to your netDb/ directory.</p>
|
||||
<p>
|
||||
With the SSU transport, the internal UDP port may be different from the external
|
||||
UDP port (in case of a firewall/NAT) - the UDP port field above specifies the
|
||||
external one and assumes they are the same, but if you want to set the internal
|
||||
port to something else, you can add "i2np.udp.internalPort=1234" to the
|
||||
<a href="configadvanced.jsp">advanced</a> config and restart the router.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - config clients</title>
|
||||
<title>I2P Router Console - config logging</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigLoggingHelper" id="logginghelper" scope="request" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - config clients</title>
|
||||
<title>I2P Router Console - config service</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
|
||||
|
@ -45,7 +45,7 @@ more information).</p>
|
||||
<p>The router by default also includes human's public domain <a href="http://www.i2p.net/sam">SAM</a> bridge,
|
||||
which other client applications (such the <a href="http://duck.i2p/i2p-bt/">bittorrent port</a>) can use.
|
||||
There is also an optimized library for doing large number calculations - jbigi - which in turn uses the
|
||||
LGPL licensed <a href="http://swox.com/gmp/">GMP</a> library, tuned for various PC architectures. For
|
||||
LGPL licensed <a href="http://swox.com/gmp/">GMP</a> library, tuned for various PC architectures. Launchers for windows users are built with <a href="http://launch4j.sourceforge.net/">Launch4J</a>, and the installer is built with <a href="http://www.izforge.com/izpack/">IzPack</a>. For
|
||||
details on other applications available, as well as their licenses, please see the
|
||||
<a href="http://www.i2p.net/licenses">license policy</a>. Source for the I2P code and most bundled
|
||||
client applications can be found on our <a href="http://www.i2p.net/download">download page</a>, and is
|
||||
|
@ -15,14 +15,16 @@
|
||||
</div>
|
||||
|
||||
<h4>
|
||||
<a href="susimail/susimail">Susimail</a> |
|
||||
<a href="susidns/">SusiDNS</a> |
|
||||
<a href="syndie/">Syndie</a> |
|
||||
<a href="i2ptunnel/">I2PTunnel</a> |
|
||||
<a href="tunnels.jsp">Tunnels</a> |
|
||||
<a href="profiles.jsp">Profiles</a> |
|
||||
<a href="netdb.jsp">NetDB</a> |
|
||||
<a href="logs.jsp">Logs</a> |
|
||||
<a href="oldconsole.jsp">Internals</a> |
|
||||
<a href="oldstats.jsp">Stats</a> |
|
||||
<a href="i2ptunnel/" target="_blank">I2PTunnel</a> |
|
||||
<a href="susimail/susimail" target="_blank">Susimail</a>
|
||||
<a href="oldconsole.jsp">Internals</a>
|
||||
<jsp:useBean class="net.i2p.router.web.NavHelper" id="navhelper" scope="request" />
|
||||
<jsp:setProperty name="navhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:getProperty name="navhelper" property="clientAppLinks" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - home</title>
|
||||
<title>I2P Router Console - internals</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<title>I2P Router Console - home</title>
|
||||
<title>I2P Router Console - statistics</title>
|
||||
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||
</head><body>
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
<b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
|
||||
<b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
|
||||
<b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
|
||||
<b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br />
|
||||
<!-- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br /> -->
|
||||
<b>Known:</b> <jsp:getProperty name="helper" property="allPeers" /><br /><%
|
||||
if (helper.getActivePeers() <= 0) {
|
||||
%><b><a href="config.jsp">check your NAT/firewall</a></b><br /><%
|
||||
|
@ -24,8 +24,8 @@ public class Connection {
|
||||
private Log _log;
|
||||
private ConnectionManager _connectionManager;
|
||||
private Destination _remotePeer;
|
||||
private byte _sendStreamId[];
|
||||
private byte _receiveStreamId[];
|
||||
private long _sendStreamId;
|
||||
private long _receiveStreamId;
|
||||
private long _lastSendTime;
|
||||
private long _lastSendId;
|
||||
private boolean _resetReceived;
|
||||
@ -72,7 +72,7 @@ public class Connection {
|
||||
private long _lifetimeDupMessageSent;
|
||||
private long _lifetimeDupMessageReceived;
|
||||
|
||||
public static final long MAX_RESEND_DELAY = 5*1000;
|
||||
public static final long MAX_RESEND_DELAY = 8*1000;
|
||||
public static final long MIN_RESEND_DELAY = 3*1000;
|
||||
|
||||
/** wait up to 5 minutes after disconnection so we can ack/close packets */
|
||||
@ -205,7 +205,7 @@ public class Connection {
|
||||
_resetSent = true;
|
||||
if (_resetSentOn <= 0)
|
||||
_resetSentOn = _context.clock().now();
|
||||
if ( (_remotePeer == null) || (_sendStreamId == null) ) return;
|
||||
if ( (_remotePeer == null) || (_sendStreamId <= 0) ) return;
|
||||
PacketLocal reply = new PacketLocal(_context, _remotePeer);
|
||||
reply.setFlag(Packet.FLAG_RESET);
|
||||
reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
|
||||
@ -256,14 +256,18 @@ public class Connection {
|
||||
remaining = 0;
|
||||
if (packet.isFlagSet(Packet.FLAG_CLOSE) || (remaining < 2)) {
|
||||
packet.setOptionalDelay(0);
|
||||
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
} else {
|
||||
int delay = _options.getRTT() / 2;
|
||||
int delay = _options.getRTO() / 2;
|
||||
packet.setOptionalDelay(delay);
|
||||
_log.debug("Requesting ack delay of " + delay + "ms for packet " + packet);
|
||||
if (delay > 0)
|
||||
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Requesting ack delay of " + delay + "ms for packet " + packet);
|
||||
}
|
||||
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
|
||||
long timeout = _options.getRTT() + MIN_RESEND_DELAY;
|
||||
long timeout = _options.getRTO();
|
||||
if (timeout > MAX_RESEND_DELAY)
|
||||
timeout = MAX_RESEND_DELAY;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -307,16 +311,20 @@ public class Connection {
|
||||
}
|
||||
|
||||
List ackPackets(long ackThrough, long nacks[]) {
|
||||
if (nacks == null) {
|
||||
_highestAckedThrough = ackThrough;
|
||||
if (ackThrough < _highestAckedThrough) {
|
||||
// dupack which won't tell us anything
|
||||
} else {
|
||||
long lowest = -1;
|
||||
for (int i = 0; i < nacks.length; i++) {
|
||||
if ( (lowest < 0) || (nacks[i] < lowest) )
|
||||
lowest = nacks[i];
|
||||
if (nacks == null) {
|
||||
_highestAckedThrough = ackThrough;
|
||||
} else {
|
||||
long lowest = -1;
|
||||
for (int i = 0; i < nacks.length; i++) {
|
||||
if ( (lowest < 0) || (nacks[i] < lowest) )
|
||||
lowest = nacks[i];
|
||||
}
|
||||
if (lowest - 1 > _highestAckedThrough)
|
||||
_highestAckedThrough = lowest - 1;
|
||||
}
|
||||
if (lowest - 1 > _highestAckedThrough)
|
||||
_highestAckedThrough = lowest - 1;
|
||||
}
|
||||
|
||||
List acked = null;
|
||||
@ -463,7 +471,9 @@ public class Connection {
|
||||
_receiver.destroy();
|
||||
if (_activityTimer != null)
|
||||
SimpleTimer.getInstance().removeEvent(_activityTimer);
|
||||
_activityTimer = null;
|
||||
//_activityTimer = null;
|
||||
if (_inputStream != null)
|
||||
_inputStream.streamErrorOccurred(new IOException("disconnected!"));
|
||||
|
||||
if (_disconnectScheduledOn < 0) {
|
||||
_disconnectScheduledOn = _context.clock().now();
|
||||
@ -514,17 +524,30 @@ public class Connection {
|
||||
synchronized (_connectLock) { _connectLock.notifyAll(); }
|
||||
}
|
||||
|
||||
private boolean _remotePeerSet = false;
|
||||
/** who are we talking with */
|
||||
public Destination getRemotePeer() { return _remotePeer; }
|
||||
public void setRemotePeer(Destination peer) { _remotePeer = peer; }
|
||||
public void setRemotePeer(Destination peer) {
|
||||
if (_remotePeerSet) throw new RuntimeException("Remote peer already set [" + _remotePeer + ", " + peer + "]");
|
||||
_remotePeerSet = true;
|
||||
_remotePeer = peer;
|
||||
}
|
||||
|
||||
private boolean _sendStreamIdSet = false;
|
||||
/** what stream do we send data to the peer on? */
|
||||
public byte[] getSendStreamId() { return _sendStreamId; }
|
||||
public void setSendStreamId(byte[] id) { _sendStreamId = id; }
|
||||
public long getSendStreamId() { return _sendStreamId; }
|
||||
public void setSendStreamId(long id) {
|
||||
if (_sendStreamIdSet) throw new RuntimeException("Send stream ID already set [" + _sendStreamId + ", " + id + "]");
|
||||
_sendStreamIdSet = true;
|
||||
_sendStreamId = id;
|
||||
}
|
||||
|
||||
private boolean _receiveStreamIdSet = false;
|
||||
/** stream the peer sends data to us on. (may be null) */
|
||||
public byte[] getReceiveStreamId() { return _receiveStreamId; }
|
||||
public void setReceiveStreamId(byte[] id) {
|
||||
public long getReceiveStreamId() { return _receiveStreamId; }
|
||||
public void setReceiveStreamId(long id) {
|
||||
if (_receiveStreamIdSet) throw new RuntimeException("Receive stream ID already set [" + _receiveStreamId + ", " + id + "]");
|
||||
_receiveStreamIdSet = true;
|
||||
_receiveStreamId = id;
|
||||
synchronized (_connectLock) { _connectLock.notifyAll(); }
|
||||
}
|
||||
@ -651,7 +674,7 @@ public class Connection {
|
||||
void waitForConnect() {
|
||||
long expiration = _context.clock().now() + _options.getConnectTimeout();
|
||||
while (true) {
|
||||
if (_connected && (_receiveStreamId != null) && (_sendStreamId != null) ) {
|
||||
if (_connected && (_receiveStreamId > 0) && (_sendStreamId > 0) ) {
|
||||
// w00t
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("waitForConnect(): Connected and we have stream IDs");
|
||||
@ -695,11 +718,19 @@ public class Connection {
|
||||
}
|
||||
|
||||
private void resetActivityTimer() {
|
||||
if (_options.getInactivityTimeout() <= 0) return;
|
||||
if (_activityTimer == null) return;
|
||||
if (_options.getInactivityTimeout() <= 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Resetting the inactivity timer, but its gone!", new Exception("where did it go?"));
|
||||
return;
|
||||
}
|
||||
if (_activityTimer == null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Resetting the inactivity timer, but its gone!", new Exception("where did it go?"));
|
||||
return;
|
||||
}
|
||||
long howLong = _activityTimer.getTimeLeft();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Resetting the inactivity timer to " + howLong);
|
||||
_log.debug("Resetting the inactivity timer to " + howLong, new Exception("Reset by"));
|
||||
// this will get rescheduled, and rescheduled, and rescheduled...
|
||||
SimpleTimer.getInstance().addEvent(_activityTimer, howLong);
|
||||
}
|
||||
@ -707,15 +738,34 @@ public class Connection {
|
||||
private class ActivityTimer implements SimpleTimer.TimedEvent {
|
||||
public void timeReached() {
|
||||
// uh, nothing more to do...
|
||||
if (!_connected) return;
|
||||
if (!_connected) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, but we are already closed");
|
||||
return;
|
||||
}
|
||||
// we got rescheduled already
|
||||
if (getTimeLeft() > 0) return;
|
||||
long left = getTimeLeft();
|
||||
if (left > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, but there is time left (" + left + ")");
|
||||
SimpleTimer.getInstance().addEvent(ActivityTimer.this, left);
|
||||
return;
|
||||
}
|
||||
// these are either going to time out or cause further rescheduling
|
||||
if (getUnackedPacketsSent() > 0) return;
|
||||
if (getUnackedPacketsSent() > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, but there are unacked packets");
|
||||
return;
|
||||
}
|
||||
// wtf, this shouldn't have been scheduled
|
||||
if (_options.getInactivityTimeout() <= 0) return;
|
||||
if (_options.getInactivityTimeout() <= 0) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, but there is no timer...");
|
||||
return;
|
||||
}
|
||||
// if one of us can't talk...
|
||||
if ( (_closeSentOn > 0) || (_closeReceivedOn > 0) ) return;
|
||||
if ( (_closeSentOn > 0) || (_closeReceivedOn > 0) ) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, but we are closing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Inactivity timeout reached, with action=" + _options.getInactivityAction());
|
||||
|
||||
// bugger it, might as well do the hard work now
|
||||
switch (_options.getInactivityAction()) {
|
||||
@ -741,7 +791,9 @@ public class Connection {
|
||||
_log.debug(buf.toString());
|
||||
}
|
||||
|
||||
disconnect(true);
|
||||
_inputStream.streamErrorOccurred(new IOException("Inactivity timeout"));
|
||||
_outputStream.streamErrorOccurred(new IOException("Inactivity timeout"));
|
||||
disconnect(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -762,18 +814,19 @@ public class Connection {
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("[Connection ");
|
||||
if (_receiveStreamId != null)
|
||||
buf.append(Base64.encode(_receiveStreamId));
|
||||
if (_receiveStreamId > 0)
|
||||
buf.append(Packet.toId(_receiveStreamId));
|
||||
else
|
||||
buf.append("unknown");
|
||||
buf.append("<-->");
|
||||
if (_sendStreamId != null)
|
||||
buf.append(Base64.encode(_sendStreamId));
|
||||
if (_sendStreamId > 0)
|
||||
buf.append(Packet.toId(_sendStreamId));
|
||||
else
|
||||
buf.append("unknown");
|
||||
buf.append(" wsize: ").append(_options.getWindowSize());
|
||||
buf.append(" cwin: ").append(_congestionWindowEnd - _highestAckedThrough);
|
||||
buf.append(" rtt: ").append(_options.getRTT());
|
||||
buf.append(" rto: ").append(_options.getRTO());
|
||||
// not synchronized to avoid some kooky races
|
||||
buf.append(" unacked outbound: ").append(_outboundPackets.size()).append(" ");
|
||||
/*
|
||||
@ -877,11 +930,14 @@ public class Connection {
|
||||
}
|
||||
// revamp various fields, in case we need to ack more, etc
|
||||
_inputStream.updateAcks(_packet);
|
||||
_packet.setOptionalDelay(getOptions().getChoke());
|
||||
int choke = getOptions().getChoke();
|
||||
_packet.setOptionalDelay(choke);
|
||||
if (choke > 0)
|
||||
_packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
_packet.setOptionalMaxSize(getOptions().getMaxMessageSize());
|
||||
_packet.setResendDelay(getOptions().getResendDelay());
|
||||
_packet.setReceiveStreamId(_receiveStreamId);
|
||||
_packet.setSendStreamId(_sendStreamId);
|
||||
//_packet.setReceiveStreamId(_receiveStreamId);
|
||||
//_packet.setSendStreamId(_sendStreamId);
|
||||
|
||||
int newWindowSize = getOptions().getWindowSize();
|
||||
|
||||
@ -950,10 +1006,10 @@ public class Connection {
|
||||
disconnect(false);
|
||||
} else {
|
||||
//long timeout = _options.getResendDelay() << numSends;
|
||||
long rtt = _options.getRTT();
|
||||
if (rtt < MIN_RESEND_DELAY)
|
||||
rtt = MIN_RESEND_DELAY;
|
||||
long timeout = rtt << (numSends-1);
|
||||
long rto = _options.getRTO();
|
||||
if (rto < MIN_RESEND_DELAY)
|
||||
rto = MIN_RESEND_DELAY;
|
||||
long timeout = rto << (numSends-1);
|
||||
if ( (timeout > MAX_RESEND_DELAY) || (timeout <= 0) )
|
||||
timeout = MAX_RESEND_DELAY;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
|
@ -2,6 +2,7 @@ package net.i2p.client.streaming;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@ -142,15 +143,18 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
|
||||
data.setValid(size);
|
||||
data.setOffset(0);
|
||||
packet.setPayload(data);
|
||||
if ( (ackOnly && !forceIncrement) && (!isFirst) )
|
||||
packet.setSequenceNum(0);
|
||||
if ( (ackOnly && !forceIncrement) && (!isFirst) )
|
||||
packet.setSequenceNum(0);
|
||||
else
|
||||
packet.setSequenceNum(con.getNextOutboundPacketNum());
|
||||
packet.setSendStreamId(con.getSendStreamId());
|
||||
packet.setReceiveStreamId(con.getReceiveStreamId());
|
||||
|
||||
con.getInputStream().updateAcks(packet);
|
||||
packet.setOptionalDelay(con.getOptions().getChoke());
|
||||
int choke = con.getOptions().getChoke();
|
||||
packet.setOptionalDelay(choke);
|
||||
if (choke > 0)
|
||||
packet.setFlag(Packet.FLAG_DELAY_REQUESTED);
|
||||
packet.setResendDelay(con.getOptions().getResendDelay());
|
||||
|
||||
if (con.getOptions().getProfile() == ConnectionOptions.PROFILE_INTERACTIVE)
|
||||
@ -166,6 +170,9 @@ class ConnectionDataReceiver implements MessageOutputStream.DataReceiver {
|
||||
packet.setOptionalFrom(con.getSession().getMyDestination());
|
||||
packet.setOptionalMaxSize(con.getOptions().getMaxMessageSize());
|
||||
}
|
||||
if (DataHelper.eq(con.getSendStreamId(), Packet.STREAM_ID_UNKNOWN)) {
|
||||
packet.setFlag(Packet.FLAG_NO_ACK);
|
||||
}
|
||||
|
||||
// don't set the closed flag if this is a plain ACK and there are outstanding
|
||||
// packets sent, otherwise the other side could receive the CLOSE prematurely,
|
||||
|
@ -127,7 +127,7 @@ class ConnectionHandler {
|
||||
reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
|
||||
reply.setAckThrough(packet.getSequenceNum());
|
||||
reply.setSendStreamId(packet.getReceiveStreamId());
|
||||
reply.setReceiveStreamId(null);
|
||||
reply.setReceiveStreamId(0);
|
||||
reply.setOptionalFrom(_manager.getSession().getMyDestination());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending RST: " + reply + " because of " + packet);
|
||||
|
@ -31,9 +31,9 @@ public class ConnectionManager {
|
||||
private PacketQueue _outboundQueue;
|
||||
private SchedulerChooser _schedulerChooser;
|
||||
private ConnectionPacketHandler _conPacketHandler;
|
||||
/** Inbound stream ID (ByteArray) to Connection map */
|
||||
/** Inbound stream ID (Long) to Connection map */
|
||||
private Map _connectionByInboundId;
|
||||
/** Ping ID (ByteArray) to PingRequest */
|
||||
/** Ping ID (Long) to PingRequest */
|
||||
private Map _pendingPings;
|
||||
private boolean _allowIncoming;
|
||||
private int _maxConcurrentStreams;
|
||||
@ -71,16 +71,16 @@ public class ConnectionManager {
|
||||
_context.statManager().createRateStat("stream.receiveActive", "How many streams are active when a new one is received (period being not yet dropped)", "Stream", new long[] { 60*60*1000, 24*60*60*1000 });
|
||||
}
|
||||
|
||||
Connection getConnectionByInboundId(byte[] id) {
|
||||
Connection getConnectionByInboundId(long id) {
|
||||
synchronized (_connectionLock) {
|
||||
return (Connection)_connectionByInboundId.get(new ByteArray(id));
|
||||
return (Connection)_connectionByInboundId.get(new Long(id));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* not guaranteed to be unique, but in case we receive more than one packet
|
||||
* on an inbound connection that we havent ack'ed yet...
|
||||
*/
|
||||
Connection getConnectionByOutboundId(byte[] id) {
|
||||
Connection getConnectionByOutboundId(long id) {
|
||||
synchronized (_connectionLock) {
|
||||
for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
||||
Connection con = (Connection)iter.next();
|
||||
@ -107,8 +107,7 @@ public class ConnectionManager {
|
||||
*/
|
||||
public Connection receiveConnection(Packet synPacket) {
|
||||
Connection con = new Connection(_context, this, _schedulerChooser, _outboundQueue, _conPacketHandler, new ConnectionOptions(_defaultOptions));
|
||||
byte receiveId[] = new byte[4];
|
||||
_context.random().nextBytes(receiveId);
|
||||
long receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||
boolean reject = false;
|
||||
int active = 0;
|
||||
int total = 0;
|
||||
@ -122,16 +121,13 @@ public class ConnectionManager {
|
||||
reject = true;
|
||||
} else {
|
||||
while (true) {
|
||||
ByteArray ba = new ByteArray(receiveId);
|
||||
Connection oldCon = (Connection)_connectionByInboundId.put(ba, con);
|
||||
Connection oldCon = (Connection)_connectionByInboundId.put(new Long(receiveId), con);
|
||||
if (oldCon == null) {
|
||||
break;
|
||||
} else {
|
||||
_connectionByInboundId.put(ba, oldCon);
|
||||
_connectionByInboundId.put(new Long(receiveId), oldCon);
|
||||
// receiveId already taken, try another
|
||||
// (need to realloc receiveId, as ba.getData() points to the old value)
|
||||
receiveId = new byte[4];
|
||||
_context.random().nextBytes(receiveId);
|
||||
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +144,7 @@ public class ConnectionManager {
|
||||
reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
|
||||
reply.setAckThrough(synPacket.getSequenceNum());
|
||||
reply.setSendStreamId(synPacket.getReceiveStreamId());
|
||||
reply.setReceiveStreamId(null);
|
||||
reply.setReceiveStreamId(0);
|
||||
reply.setOptionalFrom(_session.getMyDestination());
|
||||
// this just sends the packet - no retries or whatnot
|
||||
_outboundQueue.enqueue(reply);
|
||||
@ -160,7 +156,7 @@ public class ConnectionManager {
|
||||
con.getPacketHandler().receivePacket(synPacket, con);
|
||||
} catch (I2PException ie) {
|
||||
synchronized (_connectionLock) {
|
||||
_connectionByInboundId.remove(new ByteArray(receiveId));
|
||||
_connectionByInboundId.remove(new Long(receiveId));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -179,8 +175,7 @@ public class ConnectionManager {
|
||||
*/
|
||||
public Connection connect(Destination peer, ConnectionOptions opts) {
|
||||
Connection con = null;
|
||||
byte receiveId[] = new byte[4];
|
||||
_context.random().nextBytes(receiveId);
|
||||
long receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||
long expiration = _context.clock().now() + opts.getConnectTimeout();
|
||||
if (opts.getConnectTimeout() <= 0)
|
||||
expiration = _context.clock().now() + DEFAULT_STREAM_DELAY_MAX;
|
||||
@ -213,11 +208,10 @@ public class ConnectionManager {
|
||||
con = new Connection(_context, this, _schedulerChooser, _outboundQueue, _conPacketHandler, opts);
|
||||
con.setRemotePeer(peer);
|
||||
|
||||
ByteArray ba = new ByteArray(receiveId);
|
||||
while (_connectionByInboundId.containsKey(ba)) {
|
||||
_context.random().nextBytes(receiveId);
|
||||
while (_connectionByInboundId.containsKey(new Long(receiveId))) {
|
||||
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||
}
|
||||
_connectionByInboundId.put(ba, con);
|
||||
_connectionByInboundId.put(new Long(receiveId), con);
|
||||
break; // stop looping as a psuedo-wait
|
||||
}
|
||||
}
|
||||
@ -284,7 +278,7 @@ public class ConnectionManager {
|
||||
public void removeConnection(Connection con) {
|
||||
boolean removed = false;
|
||||
synchronized (_connectionLock) {
|
||||
Object o = _connectionByInboundId.remove(new ByteArray(con.getReceiveStreamId()));
|
||||
Object o = _connectionByInboundId.remove(new Long(con.getReceiveStreamId()));
|
||||
removed = (o == con);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connection removed? " + removed + " remaining: "
|
||||
@ -320,11 +314,9 @@ public class ConnectionManager {
|
||||
return ping(peer, timeoutMs, blocking, null, null, null);
|
||||
}
|
||||
public boolean ping(Destination peer, long timeoutMs, boolean blocking, SessionKey keyToUse, Set tagsToSend, PingNotifier notifier) {
|
||||
byte id[] = new byte[4];
|
||||
_context.random().nextBytes(id);
|
||||
ByteArray ba = new ByteArray(id);
|
||||
Long id = new Long(_context.random().nextLong(Packet.MAX_STREAM_ID-1)+1);
|
||||
PacketLocal packet = new PacketLocal(_context, peer);
|
||||
packet.setSendStreamId(id);
|
||||
packet.setSendStreamId(id.longValue());
|
||||
packet.setFlag(Packet.FLAG_ECHO);
|
||||
packet.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
|
||||
packet.setOptionalFrom(_session.getMyDestination());
|
||||
@ -336,7 +328,7 @@ public class ConnectionManager {
|
||||
PingRequest req = new PingRequest(peer, packet, notifier);
|
||||
|
||||
synchronized (_pendingPings) {
|
||||
_pendingPings.put(ba, req);
|
||||
_pendingPings.put(id, req);
|
||||
}
|
||||
|
||||
_outboundQueue.enqueue(packet);
|
||||
@ -349,10 +341,10 @@ public class ConnectionManager {
|
||||
}
|
||||
|
||||
synchronized (_pendingPings) {
|
||||
_pendingPings.remove(ba);
|
||||
_pendingPings.remove(id);
|
||||
}
|
||||
} else {
|
||||
SimpleTimer.getInstance().addEvent(new PingFailed(ba, notifier), timeoutMs);
|
||||
SimpleTimer.getInstance().addEvent(new PingFailed(id, notifier), timeoutMs);
|
||||
}
|
||||
|
||||
boolean ok = req.pongReceived();
|
||||
@ -364,17 +356,17 @@ public class ConnectionManager {
|
||||
}
|
||||
|
||||
private class PingFailed implements SimpleTimer.TimedEvent {
|
||||
private ByteArray _ba;
|
||||
private Long _id;
|
||||
private PingNotifier _notifier;
|
||||
public PingFailed(ByteArray ba, PingNotifier notifier) {
|
||||
_ba = ba;
|
||||
public PingFailed(Long id, PingNotifier notifier) {
|
||||
_id = id;
|
||||
_notifier = notifier;
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
boolean removed = false;
|
||||
synchronized (_pendingPings) {
|
||||
Object o = _pendingPings.remove(_ba);
|
||||
Object o = _pendingPings.remove(_id);
|
||||
if (o != null)
|
||||
removed = true;
|
||||
}
|
||||
@ -411,11 +403,10 @@ public class ConnectionManager {
|
||||
public boolean pongReceived() { return _ponged; }
|
||||
}
|
||||
|
||||
void receivePong(byte pingId[]) {
|
||||
ByteArray ba = new ByteArray(pingId);
|
||||
void receivePong(long pingId) {
|
||||
PingRequest req = null;
|
||||
synchronized (_pendingPings) {
|
||||
req = (PingRequest)_pendingPings.remove(ba);
|
||||
req = (PingRequest)_pendingPings.remove(new Long(pingId));
|
||||
}
|
||||
if (req != null)
|
||||
req.pong();
|
||||
|
@ -13,6 +13,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
private int _receiveWindow;
|
||||
private int _profile;
|
||||
private int _rtt;
|
||||
private int _rttDev;
|
||||
private int _rto;
|
||||
private int _trend[];
|
||||
private int _resendDelay;
|
||||
private int _sendAckDelay;
|
||||
@ -52,6 +54,8 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
public static final String PROP_SLOW_START_GROWTH_RATE_FACTOR = "i2p.streaming.slowStartGrowthRateFactor";
|
||||
|
||||
private static final int TREND_COUNT = 3;
|
||||
static final int INITIAL_WINDOW_SIZE = 4;
|
||||
static final int DEFAULT_MAX_SENDS = 8;
|
||||
|
||||
public ConnectionOptions() {
|
||||
super();
|
||||
@ -68,6 +72,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
public ConnectionOptions(ConnectionOptions opts) {
|
||||
super(opts);
|
||||
if (opts != null) {
|
||||
setMaxWindowSize(opts.getMaxWindowSize());
|
||||
setConnectDelay(opts.getConnectDelay());
|
||||
setProfile(opts.getProfile());
|
||||
setRTT(opts.getRTT());
|
||||
@ -80,7 +85,6 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
setInactivityTimeout(opts.getInactivityTimeout());
|
||||
setInactivityAction(opts.getInactivityAction());
|
||||
setInboundBufferSize(opts.getInboundBufferSize());
|
||||
setMaxWindowSize(opts.getMaxWindowSize());
|
||||
setCongestionAvoidanceGrowthRateFactor(opts.getCongestionAvoidanceGrowthRateFactor());
|
||||
setSlowStartGrowthRateFactor(opts.getSlowStartGrowthRateFactor());
|
||||
}
|
||||
@ -90,6 +94,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
super.init(opts);
|
||||
_trend = new int[TREND_COUNT];
|
||||
|
||||
setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
|
||||
setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
|
||||
setProfile(getInt(opts, PROP_PROFILE, PROFILE_BULK));
|
||||
setMaxMessageSize(getInt(opts, PROP_MAX_MESSAGE_SIZE, 4*1024));
|
||||
@ -97,22 +102,23 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
|
||||
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));
|
||||
setSendAckDelay(getInt(opts, PROP_INITIAL_ACK_DELAY, 500));
|
||||
setWindowSize(getInt(opts, PROP_INITIAL_WINDOW_SIZE, 1));
|
||||
setMaxResends(getInt(opts, PROP_MAX_RESENDS, 10));
|
||||
setWindowSize(getInt(opts, PROP_INITIAL_WINDOW_SIZE, INITIAL_WINDOW_SIZE));
|
||||
setMaxResends(getInt(opts, PROP_MAX_RESENDS, DEFAULT_MAX_SENDS));
|
||||
setWriteTimeout(getInt(opts, PROP_WRITE_TIMEOUT, -1));
|
||||
setInactivityTimeout(getInt(opts, PROP_INACTIVITY_TIMEOUT, 5*60*1000));
|
||||
setInactivityTimeout(getInt(opts, PROP_INACTIVITY_TIMEOUT, 2*60*1000));
|
||||
setInactivityAction(getInt(opts, PROP_INACTIVITY_ACTION, INACTIVITY_ACTION_DISCONNECT));
|
||||
setInboundBufferSize(getMaxMessageSize() * (Connection.MAX_WINDOW_SIZE + 2));
|
||||
setCongestionAvoidanceGrowthRateFactor(getInt(opts, PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR, 1));
|
||||
setSlowStartGrowthRateFactor(getInt(opts, PROP_SLOW_START_GROWTH_RATE_FACTOR, 1));
|
||||
|
||||
setConnectTimeout(getInt(opts, PROP_CONNECT_TIMEOUT, Connection.DISCONNECT_TIMEOUT));
|
||||
setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
|
||||
}
|
||||
|
||||
public void setProperties(Properties opts) {
|
||||
super.setProperties(opts);
|
||||
if (opts == null) return;
|
||||
if (opts.containsKey(PROP_MAX_WINDOW_SIZE))
|
||||
setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
|
||||
if (opts.containsKey(PROP_CONNECT_DELAY))
|
||||
setConnectDelay(getInt(opts, PROP_CONNECT_DELAY, -1));
|
||||
if (opts.containsKey(PROP_PROFILE))
|
||||
@ -124,17 +130,17 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
if (opts.containsKey(PROP_INITIAL_RECEIVE_WINDOW))
|
||||
setReceiveWindow(getInt(opts, PROP_INITIAL_RECEIVE_WINDOW, 1));
|
||||
if (opts.containsKey(PROP_INITIAL_RESEND_DELAY))
|
||||
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 500));
|
||||
setResendDelay(getInt(opts, PROP_INITIAL_RESEND_DELAY, 1000));
|
||||
if (opts.containsKey(PROP_INITIAL_ACK_DELAY))
|
||||
setSendAckDelay(getInt(opts, PROP_INITIAL_ACK_DELAY, 500));
|
||||
if (opts.containsKey(PROP_INITIAL_WINDOW_SIZE))
|
||||
setWindowSize(getInt(opts, PROP_INITIAL_WINDOW_SIZE, 1));
|
||||
setWindowSize(getInt(opts, PROP_INITIAL_WINDOW_SIZE, INITIAL_WINDOW_SIZE));
|
||||
if (opts.containsKey(PROP_MAX_RESENDS))
|
||||
setMaxResends(getInt(opts, PROP_MAX_RESENDS, 10));
|
||||
setMaxResends(getInt(opts, PROP_MAX_RESENDS, DEFAULT_MAX_SENDS));
|
||||
if (opts.containsKey(PROP_WRITE_TIMEOUT))
|
||||
setWriteTimeout(getInt(opts, PROP_WRITE_TIMEOUT, -1));
|
||||
if (opts.containsKey(PROP_INACTIVITY_TIMEOUT))
|
||||
setInactivityTimeout(getInt(opts, PROP_INACTIVITY_TIMEOUT, 5*60*1000));
|
||||
setInactivityTimeout(getInt(opts, PROP_INACTIVITY_TIMEOUT, 2*60*1000));
|
||||
if (opts.containsKey(PROP_INACTIVITY_ACTION))
|
||||
setInactivityAction(getInt(opts, PROP_INACTIVITY_ACTION, INACTIVITY_ACTION_DISCONNECT));
|
||||
setInboundBufferSize(getMaxMessageSize() * (Connection.MAX_WINDOW_SIZE + 2));
|
||||
@ -145,8 +151,6 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
|
||||
if (opts.containsKey(PROP_CONNECT_TIMEOUT))
|
||||
setConnectTimeout(getInt(opts, PROP_CONNECT_TIMEOUT, Connection.DISCONNECT_TIMEOUT));
|
||||
if (opts.containsKey(PROP_MAX_WINDOW_SIZE))
|
||||
setMaxWindowSize(getInt(opts, PROP_MAX_WINDOW_SIZE, Connection.MAX_WINDOW_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,6 +195,10 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
*/
|
||||
public int getRTT() { return _rtt; }
|
||||
public void setRTT(int ms) {
|
||||
if (_rto == 0) {
|
||||
_rttDev = ms;
|
||||
_rto = (int)Connection.MAX_RESEND_DELAY;
|
||||
}
|
||||
synchronized (_trend) {
|
||||
_trend[0] = _trend[1];
|
||||
_trend[1] = _trend[2];
|
||||
@ -201,10 +209,12 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
else
|
||||
_trend[2] = 0;
|
||||
}
|
||||
|
||||
_rtt = ms;
|
||||
if (_rtt > 60*1000)
|
||||
_rtt = 60*1000;
|
||||
}
|
||||
public int getRTO() { return _rto; }
|
||||
|
||||
/**
|
||||
* If we have 3 consecutive rtt increases, we are trending upwards (1), or if we have
|
||||
@ -225,7 +235,15 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
|
||||
private static final double RTT_DAMPENING = 0.9;
|
||||
|
||||
public void updateRTT(int measuredValue) {
|
||||
setRTT((int)(RTT_DAMPENING*_rtt + (1-RTT_DAMPENING)*measuredValue));
|
||||
_rttDev = _rttDev + (int)(0.25d*(Math.abs(measuredValue-_rtt)-_rttDev));
|
||||
int smoothed = (int)(RTT_DAMPENING*_rtt + (1-RTT_DAMPENING)*measuredValue);
|
||||
_rto = smoothed + (_rttDev<<2);
|
||||
if (_rto < Connection.MIN_RESEND_DELAY)
|
||||
_rto = (int)Connection.MIN_RESEND_DELAY;
|
||||
else if (_rto > Connection.MAX_RESEND_DELAY)
|
||||
_rto = (int)Connection.MAX_RESEND_DELAY;
|
||||
|
||||
setRTT(smoothed);
|
||||
}
|
||||
|
||||
/** How long after sending a packet will we wait before resending? */
|
||||
|
@ -96,16 +96,16 @@ public class ConnectionPacketHandler {
|
||||
boolean allowAck = true;
|
||||
|
||||
if ( (!packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) &&
|
||||
( (packet.getSendStreamId() == null) ||
|
||||
(packet.getReceiveStreamId() == null) ||
|
||||
(DataHelper.eq(packet.getSendStreamId(), Packet.STREAM_ID_UNKNOWN)) ||
|
||||
(DataHelper.eq(packet.getReceiveStreamId(), Packet.STREAM_ID_UNKNOWN)) ) )
|
||||
( (packet.getSendStreamId() <= 0) ||
|
||||
(packet.getReceiveStreamId() <= 0) ) )
|
||||
allowAck = false;
|
||||
|
||||
if (allowAck)
|
||||
if (allowAck) {
|
||||
isNew = con.getInputStream().messageReceived(packet.getSequenceNum(), packet.getPayload());
|
||||
else
|
||||
isNew = con.getInputStream().messageReceived(con.getInputStream().getHighestReadyBockId(), null);
|
||||
} else {
|
||||
con.getInputStream().notifyActivity();
|
||||
isNew = false;
|
||||
}
|
||||
|
||||
if ( (packet.getSequenceNum() == 0) && (packet.getPayloadSize() > 0) ) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -160,9 +160,7 @@ public class ConnectionPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE) &&
|
||||
((packet.getSendStreamId() == null) ||
|
||||
DataHelper.eq(packet.getSendStreamId(), Packet.STREAM_ID_UNKNOWN) ) ) {
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE) && (packet.getSendStreamId() <= 0) ) {
|
||||
// don't honor the ACK 0 in SYN packets received when the other side
|
||||
// has obviously not seen our messages
|
||||
} else {
|
||||
@ -170,10 +168,16 @@ public class ConnectionPacketHandler {
|
||||
}
|
||||
con.eventOccurred();
|
||||
if (fastAck) {
|
||||
if (con.getLastSendTime() + 2000 < _context.clock().now()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fast ack for dup " + packet);
|
||||
con.ackImmediately();
|
||||
if (!isNew) {
|
||||
// if we're congested (fastAck) but this is also a new packet,
|
||||
// we've already scheduled an ack above, so there is no need to schedule
|
||||
// a fast ack (we can wait a few ms)
|
||||
} else {
|
||||
if (con.getLastSendTime() + 2000 < _context.clock().now()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fast ack for dup " + packet);
|
||||
con.ackImmediately();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +191,7 @@ public class ConnectionPacketHandler {
|
||||
}
|
||||
|
||||
private boolean ack(Connection con, long ackThrough, long nacks[], Packet packet, boolean isNew, boolean choke) {
|
||||
if (ackThrough < 0) return false;
|
||||
//if ( (nacks != null) && (nacks.length > 0) )
|
||||
// con.getOptions().setRTT(con.getOptions().getRTT() + nacks.length*1000);
|
||||
|
||||
@ -196,8 +201,8 @@ public class ConnectionPacketHandler {
|
||||
// could actually be acking data (this fixes the buggered up ack of packet 0 problem).
|
||||
// this is called after packet verification, which places the stream IDs as necessary if
|
||||
// the SYN verifies (so if we're acking w/out stream IDs, no SYN has been received yet)
|
||||
if ( (packet != null) && (packet.getSendStreamId() != null) && (packet.getReceiveStreamId() != null) &&
|
||||
(con != null) && (con.getSendStreamId() != null) && (con.getReceiveStreamId() != null) &&
|
||||
if ( (packet != null) && (packet.getSendStreamId() > 0) && (packet.getReceiveStreamId() > 0) &&
|
||||
(con != null) && (con.getSendStreamId() > 0) && (con.getReceiveStreamId() > 0) &&
|
||||
(!DataHelper.eq(packet.getSendStreamId(), Packet.STREAM_ID_UNKNOWN)) &&
|
||||
(!DataHelper.eq(packet.getReceiveStreamId(), Packet.STREAM_ID_UNKNOWN)) &&
|
||||
(!DataHelper.eq(con.getSendStreamId(), Packet.STREAM_ID_UNKNOWN)) &&
|
||||
@ -315,6 +320,12 @@ public class ConnectionPacketHandler {
|
||||
return congested;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we don't know the send stream id yet (we're just creating a connection), allow
|
||||
* the first three packets to come in. The first of those should be the SYN, of course...
|
||||
*/
|
||||
private static final int MAX_INITIAL_PACKETS = ConnectionOptions.INITIAL_WINDOW_SIZE;
|
||||
|
||||
/**
|
||||
* Make sure this packet is ok and that we can continue processing its data.
|
||||
*
|
||||
@ -328,14 +339,14 @@ public class ConnectionPacketHandler {
|
||||
} else {
|
||||
verifySignature(packet, con);
|
||||
|
||||
if (con.getSendStreamId() == null) {
|
||||
if (con.getSendStreamId() <= 0) {
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
|
||||
con.setSendStreamId(packet.getReceiveStreamId());
|
||||
con.setRemotePeer(packet.getOptionalFrom());
|
||||
return true;
|
||||
} else {
|
||||
// neither RST nor SYN and we dont have the stream id yet?
|
||||
if (packet.getSequenceNum() <= 2) {
|
||||
if (packet.getSequenceNum() < MAX_INITIAL_PACKETS) {
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
|
@ -44,6 +44,7 @@ public class MessageHandler implements I2PSessionListener {
|
||||
_log.warn("Error receiving the message", ise);
|
||||
return;
|
||||
}
|
||||
if (data == null) return;
|
||||
Packet packet = new Packet();
|
||||
try {
|
||||
packet.readPacket(data, 0, data.length);
|
||||
|
@ -193,6 +193,8 @@ public class MessageInputStream extends InputStream {
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyActivity() { synchronized (_dataLock) { _dataLock.notifyAll(); } }
|
||||
|
||||
/**
|
||||
* A new message has arrived - toss it on the appropriate queue (moving
|
||||
* previously pending messages to the ready queue if it fills the gap, etc).
|
||||
@ -435,7 +437,9 @@ public class MessageInputStream extends InputStream {
|
||||
*
|
||||
*/
|
||||
void streamErrorOccurred(IOException ioe) {
|
||||
_streamError = ioe;
|
||||
if (_streamError == null)
|
||||
_streamError = ioe;
|
||||
_locallyClosed = true;
|
||||
synchronized (_dataLock) {
|
||||
_dataLock.notifyAll();
|
||||
}
|
||||
|
@ -312,11 +312,16 @@ public class MessageOutputStream extends OutputStream {
|
||||
/** nonblocking close */
|
||||
public void closeInternal() {
|
||||
_closed = true;
|
||||
_streamError = new IOException("Closed internally");
|
||||
if (_streamError == null)
|
||||
_streamError = new IOException("Closed internally");
|
||||
clearData(true);
|
||||
}
|
||||
|
||||
private void clearData(boolean shouldFlush) {
|
||||
ByteArray ba = null;
|
||||
synchronized (_dataLock) {
|
||||
// flush any data, but don't wait for it
|
||||
if (_dataReceiver != null)
|
||||
if ( (_dataReceiver != null) && (_valid > 0) && shouldFlush)
|
||||
_dataReceiver.writeData(_buf, 0, _valid);
|
||||
_written += _valid;
|
||||
_valid = 0;
|
||||
@ -345,7 +350,9 @@ public class MessageOutputStream extends OutputStream {
|
||||
}
|
||||
|
||||
void streamErrorOccurred(IOException ioe) {
|
||||
_streamError = ioe;
|
||||
if (_streamError == null)
|
||||
_streamError = ioe;
|
||||
clearData(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,7 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Contain a single packet transferred as part of a streaming connection.
|
||||
@ -51,8 +52,8 @@ import net.i2p.util.ByteCache;
|
||||
*
|
||||
*/
|
||||
public class Packet {
|
||||
private byte _sendStreamId[];
|
||||
private byte _receiveStreamId[];
|
||||
private long _sendStreamId;
|
||||
private long _receiveStreamId;
|
||||
private long _sequenceNum;
|
||||
private long _ackThrough;
|
||||
private long _nacks[];
|
||||
@ -64,7 +65,6 @@ public class Packet {
|
||||
private Destination _optionFrom;
|
||||
private int _optionDelay;
|
||||
private int _optionMaxSize;
|
||||
private ByteCache _cache;
|
||||
|
||||
/**
|
||||
* The receiveStreamId will be set to this when the packet doesn't know
|
||||
@ -72,7 +72,9 @@ public class Packet {
|
||||
* synchronize packet)
|
||||
*
|
||||
*/
|
||||
public static final byte STREAM_ID_UNKNOWN[] = new byte[] { 0x00, 0x00, 0x00, 0x00 };
|
||||
public static final long STREAM_ID_UNKNOWN = 0l;
|
||||
|
||||
public static final long MAX_STREAM_ID = 0xffffffffl;
|
||||
|
||||
/**
|
||||
* This packet is creating a new socket connection (if the receiveStreamId
|
||||
@ -135,43 +137,36 @@ public class Packet {
|
||||
* ping reply (if receiveStreamId is set).
|
||||
*/
|
||||
public static final int FLAG_ECHO = (1 << 9);
|
||||
|
||||
/**
|
||||
* If set, this packet doesn't really want to ack anything
|
||||
*/
|
||||
public static final int FLAG_NO_ACK = (1 << 10);
|
||||
|
||||
public static final int DEFAULT_MAX_SIZE = 32*1024;
|
||||
private static final int MAX_DELAY_REQUEST = 65535;
|
||||
|
||||
public Packet() {
|
||||
_cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
|
||||
}
|
||||
public Packet() { }
|
||||
|
||||
/** what stream is this packet a part of? */
|
||||
public byte[] getSendStreamId() {
|
||||
if ( (_sendStreamId == null) || (DataHelper.eq(_sendStreamId, STREAM_ID_UNKNOWN)) )
|
||||
return null;
|
||||
else
|
||||
return _sendStreamId;
|
||||
}
|
||||
public void setSendStreamId(byte[] id) {
|
||||
private boolean _sendStreamIdSet = false;
|
||||
/** what stream do we send data to the peer on? */
|
||||
public long getSendStreamId() { return _sendStreamId; }
|
||||
public void setSendStreamId(long id) {
|
||||
if (_sendStreamIdSet) throw new RuntimeException("Send stream ID already set [" + _sendStreamId + ", " + id + "]");
|
||||
_sendStreamIdSet = true;
|
||||
_sendStreamId = id;
|
||||
if ( (id != null) && (DataHelper.eq(id, STREAM_ID_UNKNOWN)) )
|
||||
_sendStreamId = null;
|
||||
}
|
||||
|
||||
private boolean _receiveStreamIdSet = false;
|
||||
/**
|
||||
* Stream that replies should be sent on. if the
|
||||
* connection is still being built, this should be
|
||||
* null.
|
||||
*
|
||||
* stream the replies should be sent on. this should be 0 if the
|
||||
* connection is still being built.
|
||||
*/
|
||||
public byte[] getReceiveStreamId() {
|
||||
if ( (_receiveStreamId == null) || (DataHelper.eq(_receiveStreamId, STREAM_ID_UNKNOWN)) )
|
||||
return null;
|
||||
else
|
||||
return _receiveStreamId;
|
||||
}
|
||||
public void setReceiveStreamId(byte[] id) {
|
||||
public long getReceiveStreamId() { return _receiveStreamId; }
|
||||
public void setReceiveStreamId(long id) {
|
||||
if (_receiveStreamIdSet) throw new RuntimeException("Receive stream ID already set [" + _receiveStreamId + ", " + id + "]");
|
||||
_receiveStreamIdSet = true;
|
||||
_receiveStreamId = id;
|
||||
if ( (id != null) && (DataHelper.eq(id, STREAM_ID_UNKNOWN)) )
|
||||
_receiveStreamId = null;
|
||||
}
|
||||
|
||||
/** 0-indexed sequence number for this Packet in the sendStream */
|
||||
@ -181,11 +176,21 @@ public class Packet {
|
||||
/**
|
||||
* The highest packet sequence number that received
|
||||
* on the receiveStreamId. This field is ignored on the initial
|
||||
* connection packet (where receiveStreamId is the unknown id).
|
||||
* connection packet (where receiveStreamId is the unknown id) or
|
||||
* if FLAG_NO_ACK is set.
|
||||
*
|
||||
*/
|
||||
public long getAckThrough() { return _ackThrough; }
|
||||
public void setAckThrough(long id) { _ackThrough = id; }
|
||||
public long getAckThrough() {
|
||||
if (isFlagSet(FLAG_NO_ACK))
|
||||
return -1;
|
||||
else
|
||||
return _ackThrough;
|
||||
}
|
||||
public void setAckThrough(long id) {
|
||||
if (id < 0)
|
||||
setFlag(FLAG_NO_ACK);
|
||||
_ackThrough = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of packet sequence numbers below the getAckThrough() value
|
||||
@ -209,8 +214,6 @@ public class Packet {
|
||||
/** get the actual payload of the message. may be null */
|
||||
public ByteArray getPayload() { return _payload; }
|
||||
public void setPayload(ByteArray payload) {
|
||||
//if ( (_payload != null) && (_payload != payload) )
|
||||
// _cache.release(_payload);
|
||||
_payload = payload;
|
||||
if ( (payload != null) && (payload.getValid() > MAX_PAYLOAD_SIZE) )
|
||||
throw new IllegalArgumentException("Too large payload: " + payload.getValid());
|
||||
@ -219,15 +222,11 @@ public class Packet {
|
||||
return (_payload == null ? 0 : _payload.getValid());
|
||||
}
|
||||
public void releasePayload() {
|
||||
//if (_payload != null)
|
||||
// _cache.release(_payload);
|
||||
_payload = null;
|
||||
//_payload = null;
|
||||
}
|
||||
public ByteArray acquirePayload() {
|
||||
ByteArray old = _payload;
|
||||
_payload = new ByteArray(new byte[Packet.MAX_PAYLOAD_SIZE]); //_cache.acquire();
|
||||
//if (old != null)
|
||||
// _cache.release(old);
|
||||
_payload = new ByteArray(new byte[Packet.MAX_PAYLOAD_SIZE]);
|
||||
return _payload;
|
||||
}
|
||||
|
||||
@ -240,6 +239,7 @@ public class Packet {
|
||||
else
|
||||
_flags &= ~flag;
|
||||
}
|
||||
public void setFlags(int flags) { _flags = flags; }
|
||||
|
||||
/** the signature on the packet (only included if the flag for it is set) */
|
||||
public Signature getOptionalSignature() { return _optionSignature; }
|
||||
@ -263,7 +263,6 @@ public class Packet {
|
||||
*/
|
||||
public int getOptionalDelay() { return _optionDelay; }
|
||||
public void setOptionalDelay(int delayMs) {
|
||||
setFlag(FLAG_DELAY_REQUESTED, delayMs > 0);
|
||||
if (delayMs > MAX_DELAY_REQUEST)
|
||||
_optionDelay = MAX_DELAY_REQUEST;
|
||||
else if (delayMs < 0)
|
||||
@ -297,15 +296,9 @@ public class Packet {
|
||||
*/
|
||||
private int writePacket(byte buffer[], int offset, boolean includeSig) throws IllegalStateException {
|
||||
int cur = offset;
|
||||
if ( (_sendStreamId != null) && (_sendStreamId.length == 4) )
|
||||
System.arraycopy(_sendStreamId, 0, buffer, cur, _sendStreamId.length);
|
||||
else
|
||||
System.arraycopy(STREAM_ID_UNKNOWN, 0, buffer, cur, STREAM_ID_UNKNOWN.length);
|
||||
DataHelper.toLong(buffer, cur, 4, (_sendStreamId >= 0 ? _sendStreamId : STREAM_ID_UNKNOWN));
|
||||
cur += 4;
|
||||
if ( (_receiveStreamId != null) && (_receiveStreamId.length == 4) )
|
||||
System.arraycopy(_receiveStreamId, 0, buffer, cur, _receiveStreamId.length);
|
||||
else
|
||||
System.arraycopy(STREAM_ID_UNKNOWN, 0, buffer, cur, STREAM_ID_UNKNOWN.length);
|
||||
DataHelper.toLong(buffer, cur, 4, (_receiveStreamId >= 0 ? _receiveStreamId : STREAM_ID_UNKNOWN));
|
||||
cur += 4;
|
||||
DataHelper.toLong(buffer, cur, 4, _sequenceNum > 0 ? _sequenceNum : 0);
|
||||
cur += 4;
|
||||
@ -383,7 +376,7 @@ public class Packet {
|
||||
size += 4; // sequenceNum
|
||||
size += 4; // ackThrough
|
||||
if (_nacks != null) {
|
||||
size++; // nacks length
|
||||
size++; // nacks length
|
||||
size += 4 * _nacks.length;
|
||||
} else {
|
||||
size++; // nacks length
|
||||
@ -425,32 +418,31 @@ public class Packet {
|
||||
if (length < 22) // min header size
|
||||
throw new IllegalArgumentException("Too small: len=" + buffer.length);
|
||||
int cur = offset;
|
||||
_sendStreamId = new byte[4];
|
||||
System.arraycopy(buffer, cur, _sendStreamId, 0, 4);
|
||||
setSendStreamId(DataHelper.fromLong(buffer, cur, 4));
|
||||
cur += 4;
|
||||
_receiveStreamId = new byte[4];
|
||||
System.arraycopy(buffer, cur, _receiveStreamId, 0, 4);
|
||||
setReceiveStreamId(DataHelper.fromLong(buffer, cur, 4));
|
||||
cur += 4;
|
||||
_sequenceNum = DataHelper.fromLong(buffer, cur, 4);
|
||||
setSequenceNum(DataHelper.fromLong(buffer, cur, 4));
|
||||
cur += 4;
|
||||
_ackThrough = DataHelper.fromLong(buffer, cur, 4);
|
||||
setAckThrough(DataHelper.fromLong(buffer, cur, 4));
|
||||
cur += 4;
|
||||
int numNacks = (int)DataHelper.fromLong(buffer, cur, 1);
|
||||
cur++;
|
||||
if (length < 22 + numNacks*4)
|
||||
throw new IllegalArgumentException("Too small with " + numNacks + " nacks: " + length);
|
||||
if (numNacks > 0) {
|
||||
_nacks = new long[numNacks];
|
||||
long nacks[] = new long[numNacks];
|
||||
for (int i = 0; i < numNacks; i++) {
|
||||
_nacks[i] = DataHelper.fromLong(buffer, cur, 4);
|
||||
nacks[i] = DataHelper.fromLong(buffer, cur, 4);
|
||||
cur += 4;
|
||||
}
|
||||
setNacks(nacks);
|
||||
} else {
|
||||
_nacks = null;
|
||||
setNacks(null);
|
||||
}
|
||||
_resendDelay = (int)DataHelper.fromLong(buffer, cur, 1);
|
||||
setResendDelay((int)DataHelper.fromLong(buffer, cur, 1));
|
||||
cur++;
|
||||
_flags = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
setFlags((int)DataHelper.fromLong(buffer, cur, 2));
|
||||
cur += 2;
|
||||
|
||||
int optionSize = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
@ -466,33 +458,36 @@ public class Packet {
|
||||
throw new IllegalArgumentException("length: " + length + " offset: " + offset + " begin: " + payloadBegin);
|
||||
|
||||
// skip ahead to the payload
|
||||
_payload = new ByteArray(new byte[payloadSize]); //_cache.acquire();
|
||||
System.arraycopy(buffer, payloadBegin, _payload.getData(), 0, payloadSize);
|
||||
_payload.setValid(payloadSize);
|
||||
_payload.setOffset(0);
|
||||
//_payload = new ByteArray(new byte[payloadSize]);
|
||||
_payload = new ByteArray(buffer, payloadBegin, payloadSize);
|
||||
//System.arraycopy(buffer, payloadBegin, _payload.getData(), 0, payloadSize);
|
||||
//_payload.setValid(payloadSize);
|
||||
//_payload.setOffset(0);
|
||||
|
||||
// ok now lets go back and deal with the options
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED)) {
|
||||
_optionDelay = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
setOptionalDelay((int)DataHelper.fromLong(buffer, cur, 2));
|
||||
cur += 2;
|
||||
}
|
||||
if (isFlagSet(FLAG_FROM_INCLUDED)) {
|
||||
_optionFrom = new Destination();
|
||||
Destination optionFrom = new Destination();
|
||||
try {
|
||||
cur += _optionFrom.readBytes(buffer, cur);
|
||||
cur += optionFrom.readBytes(buffer, cur);
|
||||
setOptionalFrom(optionFrom);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new IllegalArgumentException("Bad from field: " + dfe.getMessage());
|
||||
}
|
||||
}
|
||||
if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED)) {
|
||||
_optionMaxSize = (int)DataHelper.fromLong(buffer, cur, 2);
|
||||
setOptionalMaxSize((int)DataHelper.fromLong(buffer, cur, 2));
|
||||
cur += 2;
|
||||
}
|
||||
if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
|
||||
_optionSignature = new Signature();
|
||||
Signature optionSignature = new Signature();
|
||||
byte buf[] = new byte[Signature.SIGNATURE_BYTES];
|
||||
System.arraycopy(buffer, cur, buf, 0, Signature.SIGNATURE_BYTES);
|
||||
_optionSignature.setData(buf);
|
||||
optionSignature.setData(buf);
|
||||
setOptionalSignature(optionSignature);
|
||||
cur += Signature.SIGNATURE_BYTES;
|
||||
}
|
||||
}
|
||||
@ -518,7 +513,12 @@ public class Packet {
|
||||
}
|
||||
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, from.getSigningPublicKey());
|
||||
if (!ok) {
|
||||
ctx.logManager().getLog(Packet.class).error("Signature failed on " + toString(), new Exception("moo"));
|
||||
Log l = ctx.logManager().getLog(Packet.class);
|
||||
l.error("Signature failed on " + toString(), new Exception("moo"));
|
||||
if (false) {
|
||||
l.error(Base64.encode(buffer, 0, size));
|
||||
l.error("Signature: " + Base64.encode(_optionSignature.getData()));
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -533,6 +533,12 @@ public class Packet {
|
||||
setFlag(FLAG_SIGNATURE_INCLUDED);
|
||||
int size = writePacket(buffer, offset, false);
|
||||
_optionSignature = ctx.dsa().sign(buffer, offset, size, key);
|
||||
if (false) {
|
||||
Log l = ctx.logManager().getLog(Packet.class);
|
||||
l.error("Signing: " + toString());
|
||||
l.error(Base64.encode(buffer, 0, size));
|
||||
l.error("Signature: " + Base64.encode(_optionSignature.getData()));
|
||||
}
|
||||
// jump into the signed data and inject the signature where we
|
||||
// previously placed a bunch of zeroes
|
||||
int signatureOffset = offset
|
||||
@ -566,7 +572,7 @@ public class Packet {
|
||||
else
|
||||
buf.append('\t');
|
||||
buf.append(toFlagString());
|
||||
buf.append(" ACK ").append(_ackThrough);
|
||||
buf.append(" ACK ").append(getAckThrough());
|
||||
if (_nacks != null) {
|
||||
buf.append(" NACK");
|
||||
for (int i = 0; i < _nacks.length; i++) {
|
||||
@ -578,11 +584,8 @@ public class Packet {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static final String toId(byte id[]) {
|
||||
if (id == null)
|
||||
return Base64.encode(STREAM_ID_UNKNOWN);
|
||||
else
|
||||
return Base64.encode(id);
|
||||
static final String toId(long id) {
|
||||
return Base64.encode(DataHelper.toLong(4, id));
|
||||
}
|
||||
|
||||
private final String toFlagString() {
|
||||
|
@ -22,19 +22,26 @@ public class PacketHandler {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private int _lastDelay;
|
||||
private int _dropped;
|
||||
|
||||
public PacketHandler(I2PAppContext ctx, ConnectionManager mgr) {
|
||||
_manager = mgr;
|
||||
_context = ctx;
|
||||
_dropped = 0;
|
||||
_log = ctx.logManager().getLog(PacketHandler.class);
|
||||
_lastDelay = _context.random().nextInt(30*1000);
|
||||
}
|
||||
|
||||
private boolean choke(Packet packet) {
|
||||
if (false) {
|
||||
// artificial choke: 2% random drop and a 0-30s
|
||||
private boolean choke(Packet packet) {
|
||||
if (true) return true;
|
||||
//if ( (_dropped == 0) && true ) { //&& (_manager.getSent() <= 0) ) {
|
||||
// _dropped++;
|
||||
// return false;
|
||||
//}
|
||||
if (true) {
|
||||
// artificial choke: 2% random drop and a 0-5s
|
||||
// random tiered delay from 0-30s
|
||||
if (_context.random().nextInt(100) >= 95) {
|
||||
if (_context.random().nextInt(100) >= 98) {
|
||||
displayPacket(packet, "DROP", null);
|
||||
return false;
|
||||
} else {
|
||||
@ -42,7 +49,7 @@ public class PacketHandler {
|
||||
/*
|
||||
int delay = _context.random().nextInt(5*1000);
|
||||
*/
|
||||
int delay = _context.random().nextInt(6*1000);
|
||||
int delay = _context.random().nextInt(1*1000);
|
||||
int delayFactor = _context.random().nextInt(100);
|
||||
if (delayFactor > 80) {
|
||||
if (delayFactor > 98)
|
||||
@ -90,14 +97,12 @@ public class PacketHandler {
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("packet received: " + packet);
|
||||
|
||||
byte sendId[] = packet.getSendStreamId();
|
||||
if (!isNonZero(sendId))
|
||||
sendId = null;
|
||||
long sendId = packet.getSendStreamId();
|
||||
|
||||
Connection con = (sendId != null ? _manager.getConnectionByInboundId(sendId) : null);
|
||||
Connection con = (sendId > 0 ? _manager.getConnectionByInboundId(sendId) : null);
|
||||
if (con != null) {
|
||||
receiveKnownCon(con, packet);
|
||||
displayPacket(packet, "RECV", "wsize " + con.getOptions().getWindowSize());
|
||||
displayPacket(packet, "RECV", "wsize " + con.getOptions().getWindowSize() + " rto " + con.getOptions().getRTO());
|
||||
} else {
|
||||
receiveUnknownCon(packet, sendId);
|
||||
displayPacket(packet, "UNKN", null);
|
||||
@ -120,9 +125,9 @@ public class PacketHandler {
|
||||
|
||||
private void receiveKnownCon(Connection con, Packet packet) {
|
||||
if (packet.isFlagSet(Packet.FLAG_ECHO)) {
|
||||
if (packet.getSendStreamId() != null) {
|
||||
if (packet.getSendStreamId() > 0) {
|
||||
receivePing(packet);
|
||||
} else if (packet.getReceiveStreamId() != null) {
|
||||
} else if (packet.getReceiveStreamId() > 0) {
|
||||
receivePong(packet);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@ -155,17 +160,17 @@ public class PacketHandler {
|
||||
_log.warn("Received forged reset for " + con, ie);
|
||||
}
|
||||
} else {
|
||||
if ( (con.getSendStreamId() == null) ||
|
||||
if ( (con.getSendStreamId() <= 0) ||
|
||||
(DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) ) {
|
||||
byte oldId[] =con.getSendStreamId();
|
||||
long oldId =con.getSendStreamId();
|
||||
if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) // con fully established, w00t
|
||||
con.setSendStreamId(packet.getReceiveStreamId());
|
||||
|
||||
try {
|
||||
con.getPacketHandler().receivePacket(packet, con);
|
||||
} catch (I2PException ie) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Received forged packet for " + con + ": " + packet, ie);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Received forged packet for " + con + "/" + oldId + ": " + packet, ie);
|
||||
con.setSendStreamId(oldId);
|
||||
}
|
||||
} else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
|
||||
@ -207,11 +212,11 @@ public class PacketHandler {
|
||||
_manager.getPacketQueue().enqueue(reply);
|
||||
}
|
||||
|
||||
private void receiveUnknownCon(Packet packet, byte sendId[]) {
|
||||
private void receiveUnknownCon(Packet packet, long sendId) {
|
||||
if (packet.isFlagSet(Packet.FLAG_ECHO)) {
|
||||
if (packet.getSendStreamId() != null) {
|
||||
if (packet.getSendStreamId() > 0) {
|
||||
receivePing(packet);
|
||||
} else if (packet.getReceiveStreamId() != null) {
|
||||
} else if (packet.getReceiveStreamId() > 0) {
|
||||
receivePong(packet);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@ -221,7 +226,7 @@ public class PacketHandler {
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Packet received on an unknown stream (and not an ECHO): " + packet);
|
||||
if (sendId == null) {
|
||||
if (sendId <= 0) {
|
||||
Connection con = _manager.getConnectionByOutboundId(packet.getReceiveStreamId());
|
||||
if (con != null) {
|
||||
if (con.getAckedPackets() <= 0) {
|
||||
@ -250,7 +255,7 @@ public class PacketHandler {
|
||||
}
|
||||
_log.warn("Packet belongs to no other cons: " + packet + " connections: "
|
||||
+ buf.toString() + " sendId: "
|
||||
+ (sendId != null ? Base64.encode(sendId) : " unknown"));
|
||||
+ (sendId > 0 ? Packet.toId(sendId) : " unknown"));
|
||||
}
|
||||
packet.releasePayload();
|
||||
}
|
||||
@ -282,25 +287,7 @@ public class PacketHandler {
|
||||
_manager.receivePong(packet.getReceiveStreamId());
|
||||
}
|
||||
|
||||
private static final boolean isValidMatch(byte conStreamId[], byte packetStreamId[]) {
|
||||
if ( (conStreamId == null) || (packetStreamId == null) ||
|
||||
(conStreamId.length != packetStreamId.length) )
|
||||
return false;
|
||||
|
||||
boolean nonZeroFound = false;
|
||||
for (int i = 0; i < conStreamId.length; i++) {
|
||||
if (conStreamId[i] != packetStreamId[i]) return false;
|
||||
if (conStreamId[i] != 0x0) nonZeroFound = true;
|
||||
}
|
||||
return nonZeroFound;
|
||||
}
|
||||
|
||||
private static final boolean isNonZero(byte[] b) {
|
||||
boolean nonZeroFound = false;
|
||||
for (int i = 0; b != null && i < b.length; i++) {
|
||||
if (b[i] != 0x0)
|
||||
nonZeroFound = true;
|
||||
}
|
||||
return nonZeroFound;
|
||||
private static final boolean isValidMatch(long conStreamId, long packetStreamId) {
|
||||
return ( (conStreamId == packetStreamId) && (conStreamId != 0) );
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.util.Set;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
@ -27,7 +26,6 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
private long _ackOn;
|
||||
private long _cancelledOn;
|
||||
private SimpleTimer.TimedEvent _resendEvent;
|
||||
private ByteCache _cache = ByteCache.getInstance(128, MAX_PAYLOAD_SIZE);
|
||||
|
||||
public PacketLocal(I2PAppContext ctx, Destination to) {
|
||||
this(ctx, to, null);
|
||||
@ -71,8 +69,11 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat
|
||||
public void prepare() {
|
||||
if (_connection != null)
|
||||
_connection.getInputStream().updateAcks(this);
|
||||
if (_numSends > 0) // so we can debug to differentiate resends
|
||||
if (_numSends > 0) {
|
||||
// so we can debug to differentiate resends
|
||||
setOptionalDelay(_numSends * 1000);
|
||||
setFlag(FLAG_DELAY_REQUESTED);
|
||||
}
|
||||
}
|
||||
|
||||
public long getCreatedOn() { return _createdOn; }
|
||||
|
@ -125,7 +125,7 @@ class PacketQueue {
|
||||
_log.debug(msg);
|
||||
}
|
||||
Connection c = packet.getConnection();
|
||||
String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() : null);
|
||||
String suffix = (c != null ? "wsize " + c.getOptions().getWindowSize() + " rto " + c.getOptions().getRTO() : null);
|
||||
_connectionManager.getPacketHandler().displayPacket(packet, "SEND", suffix);
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ class SchedulerClosed extends SchedulerImpl {
|
||||
(!con.getResetReceived()) &&
|
||||
(timeSinceClose < Connection.DISCONNECT_TIMEOUT);
|
||||
boolean conTimeout = (con.getOptions().getConnectTimeout() < con.getLifetime()) &&
|
||||
con.getSendStreamId() == null &&
|
||||
con.getSendStreamId() <= 0 &&
|
||||
con.getLifetime() < Connection.DISCONNECT_TIMEOUT;
|
||||
return (ok || conTimeout);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class SchedulerDead extends SchedulerImpl {
|
||||
boolean nothingLeftToDo = (con.getDisconnectScheduledOn() > 0) &&
|
||||
(timeSinceClose >= Connection.DISCONNECT_TIMEOUT);
|
||||
boolean timedOut = (con.getOptions().getConnectTimeout() < con.getLifetime()) &&
|
||||
con.getSendStreamId() == null &&
|
||||
con.getSendStreamId() <= 0 &&
|
||||
con.getLifetime() >= Connection.DISCONNECT_TIMEOUT;
|
||||
return nothingLeftToDo || timedOut;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class SchedulerPreconnect extends SchedulerImpl {
|
||||
|
||||
public boolean accept(Connection con) {
|
||||
return (con != null) &&
|
||||
(con.getSendStreamId() == null) &&
|
||||
(con.getSendStreamId() <= 0) &&
|
||||
(con.getLastSendId() < 0);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ class SchedulerReceived extends SchedulerImpl {
|
||||
public boolean accept(Connection con) {
|
||||
return (con != null) &&
|
||||
(con.getLastSendId() < 0) &&
|
||||
(con.getSendStreamId() != null);
|
||||
(con.getSendStreamId() > 0);
|
||||
}
|
||||
|
||||
public void eventOccurred(Connection con) {
|
||||
|
4
apps/susidns/readme.txt
Normal file
@ -0,0 +1,4 @@
|
||||
The src/ dir contains susidns 0.13 retrieved from http://susi.i2p/ on 2005/09/15
|
||||
The contents are released under GPL. Please see http://susi.i2p/ for more info
|
||||
The paths in the src/build.xml were updated to reference jars in the i2p
|
||||
source tree.
|
BIN
apps/susidns/src/WEB-INF/lib/jstl.jar
Normal file
BIN
apps/susidns/src/WEB-INF/lib/standard.jar
Normal file
17
apps/susidns/src/WEB-INF/web-template.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE web-app
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
|
||||
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
|
||||
<web-app>
|
||||
<display-name>susidns</display-name>
|
||||
<!-- precompiled servlets -->
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
30
|
||||
</session-timeout>
|
||||
</session-config>
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
80
apps/susidns/src/build.xml
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project name="susidns" default="all" basedir=".">
|
||||
<property name="jetty" value="../../jetty/" />
|
||||
<property name="project" value="susidns" />
|
||||
<property name="src" value="java/src" />
|
||||
<property name="bin" value="./WEB-INF/classes" />
|
||||
<property name="lib" value="${jetty}/jettylib" />
|
||||
<property name="tmp" value="./tmp" />
|
||||
<property name="jsp" value="./jsp" />
|
||||
<path id="cp">
|
||||
<pathelement path="${classpath}" />
|
||||
<pathelement location="${bin}" />
|
||||
<pathelement location="${lib}/javax.servlet.jar"/>
|
||||
<pathelement location="${lib}/org.mortbay.jetty.jar"/>
|
||||
<pathelement location="WEB-INF/lib/jstl.jar" />
|
||||
<pathelement location="WEB-INF/lib/standard.jar" />
|
||||
<pathelement location="${lib}/jasper-compiler.jar" />
|
||||
<pathelement location="${lib}/jasper-runtime.jar" />
|
||||
<pathelement location="${lib}/javax.servlet.jar" />
|
||||
<pathelement location="${lib}/commons-logging.jar" />
|
||||
<pathelement location="${lib}/commons-el.jar" />
|
||||
<pathelement location="${lib}/ant.jar" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
</path>
|
||||
<target name="compile">
|
||||
<mkdir dir="${bin}" />
|
||||
<javac debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
classpathref="cp" destdir="${bin}" srcdir="${src}" includes="**/*.java" />
|
||||
</target>
|
||||
<target name="precompilejsp">
|
||||
<delete file="WEB-INF/web-fragment.xml" />
|
||||
<delete file="WEB-INF/web-out.xml" />
|
||||
<mkdir dir="${tmp}" />
|
||||
<java classname="org.apache.jasper.JspC" fork="true" classpathref="cp">
|
||||
<arg value="-d" />
|
||||
<arg value="WEB-INF/classes" />
|
||||
<arg value="-v" />
|
||||
<arg value="-p" />
|
||||
<arg value="i2p.susi.dns.jsp" />
|
||||
<arg value="-webinc" />
|
||||
<arg value="WEB-INF/web-fragment.xml" />
|
||||
<arg value="-webapp" />
|
||||
<arg value="./jsp" />
|
||||
</java>
|
||||
<javac debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="${bin}" srcdir="./WEB-INF/classes" includes="**/*.java" classpathref="cp">
|
||||
</javac>
|
||||
<copy file="WEB-INF/web-template.xml" tofile="WEB-INF/web-out.xml" />
|
||||
<loadfile property="jspc.web.fragment" srcfile="WEB-INF/web-fragment.xml" />
|
||||
<replace file="WEB-INF//web-out.xml">
|
||||
<replacefilter token="<!-- precompiled servlets -->" value="${jspc.web.fragment}" />
|
||||
</replace>
|
||||
</target>
|
||||
<target name="all" depends="compile,precompilejsp,war"/>
|
||||
<target name="war">
|
||||
<war destfile="${project}.war" webxml="WEB-INF/web-out.xml">
|
||||
<fileset dir=".">
|
||||
<include name="WEB-INF/**/*.class"/>
|
||||
<include name="WEB-INF/lib/*.jar"/>
|
||||
<include name="${src}/**/*.java"/>
|
||||
<include name="jsp/*.jsp"/>
|
||||
<include name="images/*.png"/>
|
||||
<include name="css.css"/>
|
||||
<include name="index.html"/>
|
||||
<include name="build.xml"/>
|
||||
<include name="WEB-INF/web-template.xml"/>
|
||||
<include name="WEB-INF/web-out.xml"/>
|
||||
<include name="WEB-INF/classes/${project}.properties"/>
|
||||
</fileset>
|
||||
</war>
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete file="susidns.war" />
|
||||
<delete>
|
||||
<fileset dir="." includes="**/*.class" />
|
||||
<fileset dir="." includes="tmp" />
|
||||
</delete>
|
||||
</target>
|
||||
<target name="distclean" depends="clean" />
|
||||
</project>
|
94
apps/susidns/src/css.css
Normal file
@ -0,0 +1,94 @@
|
||||
p {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
span.addrhlpr {
|
||||
font-size:7pt;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
font-size:12pt;
|
||||
letter-spacing:2pt;
|
||||
line-height:18pt;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
color:black;
|
||||
}
|
||||
|
||||
a {
|
||||
color:#327BBF;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
th {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
td {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
vertical-align:center;
|
||||
}
|
||||
|
||||
li {
|
||||
font-family:Verdana,Tahoma,Arial,Helvetica;
|
||||
color:black;
|
||||
line-height:12pt;
|
||||
margin-left:5mm;
|
||||
margin-right:5mm;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
tr.list1 {
|
||||
background-color:#E0E0E0;
|
||||
}
|
||||
|
||||
tr.list0 {
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
p.messages {
|
||||
background-color:#92CAFF;
|
||||
color:#327BBF;
|
||||
color:black;
|
||||
border-style:dotted;
|
||||
padding-top: 5mm;
|
||||
padding-right: 5mm;
|
||||
padding-bottom: 5mm;
|
||||
padding-left: 5mm;
|
||||
}
|
||||
|
||||
#help {
|
||||
border-style:dotted;
|
||||
padding-top: 5mm;
|
||||
padding-right: 5mm;
|
||||
padding-bottom: 5mm;
|
||||
padding-left: 5mm;
|
||||
}
|
||||
|
||||
p.footer {
|
||||
font-size:7pt;
|
||||
}
|
BIN
apps/susidns/src/images/add.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
apps/susidns/src/images/delete.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
apps/susidns/src/images/how.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
apps/susidns/src/images/logo.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
apps/susidns/src/images/reload.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
apps/susidns/src/images/save.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
apps/susidns/src/images/search.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
11
apps/susidns/src/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0;url=index.jsp" />
|
||||
<title>susidns</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="index.jsp">Enter</a>
|
||||
</body>
|
||||
</html>
|
||||
|
61
apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
public class AddressBean
|
||||
{
|
||||
private String name, destination;
|
||||
|
||||
public AddressBean()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AddressBean(String name, String destination)
|
||||
{
|
||||
this.name = name;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public String getDestination()
|
||||
{
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(String destination)
|
||||
{
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.2 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class AddressByNameSorter implements Comparator
|
||||
{
|
||||
public int compare(Object arg0, Object arg1)
|
||||
{
|
||||
AddressBean a = (AddressBean)arg0;
|
||||
AddressBean b = (AddressBean)arg1;
|
||||
|
||||
if( a == null )
|
||||
return 1;
|
||||
|
||||
if( b == null )
|
||||
return -1;
|
||||
|
||||
return a.getName().compareToIgnoreCase(b.getName());
|
||||
}
|
||||
}
|
262
apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java
Normal file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.7 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Properties;
|
||||
|
||||
public class AddressbookBean
|
||||
{
|
||||
private String book, action, serial, lastSerial, filter, search, hostname, destination;
|
||||
private Properties properties, addressbook;
|
||||
private int trClass;
|
||||
private LinkedList deletionMarks;
|
||||
private static Comparator sorter;
|
||||
|
||||
static {
|
||||
sorter = new AddressByNameSorter();
|
||||
}
|
||||
public String getSearch() {
|
||||
return search;
|
||||
}
|
||||
public void setSearch(String search) {
|
||||
this.search = search;
|
||||
}
|
||||
public boolean isHasFilter()
|
||||
{
|
||||
return filter != null && filter.length() > 0;
|
||||
}
|
||||
public void setTrClass(int trClass) {
|
||||
this.trClass = trClass;
|
||||
}
|
||||
public int getTrClass() {
|
||||
trClass = 1 - trClass;
|
||||
return trClass;
|
||||
}
|
||||
public boolean isIsEmpty()
|
||||
{
|
||||
return ! isNotEmpty();
|
||||
}
|
||||
public boolean isNotEmpty()
|
||||
{
|
||||
return addressbook != null && addressbook.size() > 0;
|
||||
}
|
||||
public AddressbookBean()
|
||||
{
|
||||
properties = new Properties();
|
||||
deletionMarks = new LinkedList();
|
||||
}
|
||||
private long configLastLoaded = 0;
|
||||
private void loadConfig()
|
||||
{
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
if( properties.size() > 0 && currentTime - configLastLoaded < 10000 )
|
||||
return;
|
||||
|
||||
try {
|
||||
properties.clear();
|
||||
properties.load( new FileInputStream( ConfigBean.configFileName ) );
|
||||
configLastLoaded = currentTime;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Debug.debug( e.getClass().getName() + ": " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
public String getFileName()
|
||||
{
|
||||
loadConfig();
|
||||
String filename = properties.getProperty( getBook() + "_addressbook" );
|
||||
return ConfigBean.addressbookPrefix + filename;
|
||||
}
|
||||
private Object[] entries;
|
||||
|
||||
public Object[] getEntries()
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
public String getBook()
|
||||
{
|
||||
if( book == null || ( book.compareToIgnoreCase( "master" ) != 0 &&
|
||||
book.compareToIgnoreCase( "router" ) != 0 ) &&
|
||||
book.compareToIgnoreCase( "published" ) != 0 )
|
||||
book = "master";
|
||||
|
||||
return book;
|
||||
}
|
||||
public void setBook(String book) {
|
||||
this.book = book;
|
||||
}
|
||||
public String getSerial() {
|
||||
lastSerial = "" + Math.random();
|
||||
action = null;
|
||||
return lastSerial;
|
||||
}
|
||||
public void setSerial(String serial) {
|
||||
this.serial = serial;
|
||||
}
|
||||
public String getMessages()
|
||||
{
|
||||
loadConfig();
|
||||
|
||||
String message = "";
|
||||
|
||||
if( action != null ) {
|
||||
if( lastSerial != null && serial != null && serial.compareTo( lastSerial ) == 0 ) {
|
||||
boolean changed = false;
|
||||
if( action.compareToIgnoreCase( "add") == 0 ) {
|
||||
if( addressbook != null && hostname != null && destination != null ) {
|
||||
addressbook.put( hostname, destination );
|
||||
changed = true;
|
||||
message += "Destination added.<br/>";
|
||||
}
|
||||
}
|
||||
if( action.compareToIgnoreCase( "delete" ) == 0 ) {
|
||||
Iterator it = deletionMarks.iterator();
|
||||
int deleted = 0;
|
||||
while( it.hasNext() ) {
|
||||
String name = (String)it.next();
|
||||
addressbook.remove( name );
|
||||
changed = true;
|
||||
deleted++;
|
||||
}
|
||||
if( changed ) {
|
||||
message += "" + deleted + " destination(s) deleted.<br/>";
|
||||
}
|
||||
}
|
||||
if( changed ) {
|
||||
try {
|
||||
save();
|
||||
message += "Addressbook saved.<br/>";
|
||||
} catch (Exception e) {
|
||||
Debug.debug( e.getClass().getName() + ": " + e.getMessage() );
|
||||
message += "ERROR: Could not write addressbook file.<br/>";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
message += "Invalid nonce. Are you being spoofed?";
|
||||
}
|
||||
}
|
||||
|
||||
action = null;
|
||||
|
||||
addressbook = new Properties();
|
||||
|
||||
try {
|
||||
addressbook.load( new FileInputStream( getFileName() ) );
|
||||
LinkedList list = new LinkedList();
|
||||
Enumeration e = addressbook.keys();
|
||||
while( e.hasMoreElements() ) {
|
||||
String name = (String)e.nextElement();
|
||||
String destination = addressbook.getProperty( name );
|
||||
if( filter != null && filter.length() > 0 ) {
|
||||
if( filter.compareTo( "0-9" ) == 0 ) {
|
||||
char first = name.charAt(0);
|
||||
if( first < '0' || first > '9' )
|
||||
continue;
|
||||
}
|
||||
else if( ! name.toLowerCase().startsWith( filter.toLowerCase() ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( search != null && search.length() > 0 ) {
|
||||
if( name.indexOf( search ) == -1 ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
list.addLast( new AddressBean( name, destination ) );
|
||||
}
|
||||
|
||||
Object array[] = list.toArray();
|
||||
Arrays.sort( array, sorter );
|
||||
entries = array;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Debug.debug( e.getClass().getName() + ": " + e.getMessage() );
|
||||
}
|
||||
|
||||
if( message.length() > 0 )
|
||||
message = "<p class=\"messages\">" + message + "</p>";
|
||||
return message;
|
||||
}
|
||||
|
||||
private void save() throws IOException
|
||||
{
|
||||
String filename = properties.getProperty( getBook() + "_addressbook" );
|
||||
|
||||
addressbook.store( new FileOutputStream( ConfigBean.addressbookPrefix + filename ), null );
|
||||
}
|
||||
public String getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public boolean isMaster()
|
||||
{
|
||||
return getBook().compareToIgnoreCase( "master" ) == 0;
|
||||
}
|
||||
public boolean isRouter()
|
||||
{
|
||||
return getBook().compareToIgnoreCase( "router" ) == 0;
|
||||
}
|
||||
public void setFilter(String filter) {
|
||||
if( filter != null && ( filter.length() == 0 || filter.compareToIgnoreCase( "none" ) == 0 ) ) {
|
||||
filter = null;
|
||||
search = null;
|
||||
}
|
||||
this.filter = filter;
|
||||
}
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
public void setResetDeletionMarks( String dummy ) {
|
||||
deletionMarks.clear();
|
||||
}
|
||||
public void setMarkedForDeletion( String name ) {
|
||||
deletionMarks.addLast( name );
|
||||
}
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
}
|
157
apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ConfigBean implements Serializable {
|
||||
|
||||
/*
|
||||
* as this is not provided as constant in addressbook, we define it here
|
||||
*/
|
||||
public static String addressbookPrefix = "addressbook/";
|
||||
public static String configFileName = addressbookPrefix + "config.txt";
|
||||
|
||||
private String action, config;
|
||||
private String serial, lastSerial;
|
||||
private boolean saved;
|
||||
|
||||
public static String getConfigFileName() {
|
||||
return configFileName;
|
||||
}
|
||||
|
||||
public String getfileName() {
|
||||
return getConfigFileName();
|
||||
}
|
||||
|
||||
public boolean isSaved() {
|
||||
return saved;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getConfig()
|
||||
{
|
||||
if( config != null )
|
||||
return config;
|
||||
|
||||
reload();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private void reload()
|
||||
{
|
||||
File file = new File( configFileName );
|
||||
if( file != null && file.isFile() ) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
try {
|
||||
BufferedReader br = new BufferedReader( new FileReader( file ) );
|
||||
String line;
|
||||
while( ( line = br.readLine() ) != null ) {
|
||||
buf.append( line );
|
||||
buf.append( "\n" );
|
||||
}
|
||||
config = buf.toString();
|
||||
saved = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void save()
|
||||
{
|
||||
File file = new File( configFileName );
|
||||
try {
|
||||
PrintWriter out = new PrintWriter( new FileOutputStream( file ) );
|
||||
out.print( config );
|
||||
out.flush();
|
||||
out.close();
|
||||
saved = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void setConfig(String config) {
|
||||
this.config = config;
|
||||
this.saved = false;
|
||||
|
||||
/*
|
||||
* as this is a property file we need a newline at the end of the last line!
|
||||
*/
|
||||
if( ! this.config.endsWith( "\n" ) ) {
|
||||
this.config += "\n";
|
||||
}
|
||||
}
|
||||
public String getMessages() {
|
||||
String message = "";
|
||||
if( action != null ) {
|
||||
if( lastSerial != null && serial != null && serial.compareTo( lastSerial ) == 0 ) {
|
||||
if( action.compareToIgnoreCase( "save") == 0 ) {
|
||||
save();
|
||||
message = "Configuration saved.";
|
||||
}
|
||||
else if( action.compareToIgnoreCase( "reload") == 0 ) {
|
||||
reload();
|
||||
message = "Configuration reloaded.";
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = "Invalid nonce. Are you being spoofed?";
|
||||
}
|
||||
}
|
||||
if( message.length() > 0 )
|
||||
message = "<p class=\"messages\">" + message + "</p>";
|
||||
return message;
|
||||
}
|
||||
public String getSerial()
|
||||
{
|
||||
lastSerial = "" + Math.random();
|
||||
action = null;
|
||||
return lastSerial;
|
||||
}
|
||||
public void setSerial(String serial ) {
|
||||
this.serial = serial;
|
||||
}
|
||||
}
|
56
apps/susidns/src/java/src/i2p/susi/dns/Debug.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class Debug
|
||||
{
|
||||
private static Log _log;
|
||||
private static I2PAppContext _context;
|
||||
|
||||
static
|
||||
{
|
||||
try {
|
||||
_context = I2PAppContext.getGlobalContext(); // new I2PAppContext();
|
||||
_log = _context.logManager().getLog(Debug.class);
|
||||
}
|
||||
catch( NoClassDefFoundError e ) {
|
||||
_context = null;
|
||||
_log = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void debug( String msg )
|
||||
{
|
||||
if( _log != null ) {
|
||||
_log.debug( msg );
|
||||
}
|
||||
else {
|
||||
System.err.println( "DEBUG: [susidns] " + msg );
|
||||
}
|
||||
}
|
||||
}
|
171
apps/susidns/src/java/src/i2p/susi/dns/SubscriptionsBean.java
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Properties;
|
||||
|
||||
public class SubscriptionsBean
|
||||
{
|
||||
private String action, fileName, content, serial, lastSerial;
|
||||
private boolean saved;
|
||||
|
||||
Properties properties;
|
||||
|
||||
public SubscriptionsBean()
|
||||
{
|
||||
properties = new Properties();
|
||||
}
|
||||
private long configLastLoaded = 0;
|
||||
private void loadConfig()
|
||||
{
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
if( properties.size() > 0 && currentTime - configLastLoaded < 10000 )
|
||||
return;
|
||||
|
||||
try {
|
||||
properties.clear();
|
||||
properties.load( new FileInputStream( ConfigBean.configFileName ) );
|
||||
configLastLoaded = currentTime;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Debug.debug( e.getClass().getName() + ": " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
loadConfig();
|
||||
|
||||
fileName = ConfigBean.addressbookPrefix + properties.getProperty( "subscriptions", "subscriptions.txt" );
|
||||
|
||||
return fileName;
|
||||
}
|
||||
private void reload()
|
||||
{
|
||||
File file = new File( getFileName() );
|
||||
if( file != null && file.isFile() ) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
try {
|
||||
BufferedReader br = new BufferedReader( new FileReader( file ) );
|
||||
String line;
|
||||
while( ( line = br.readLine() ) != null ) {
|
||||
buf.append( line );
|
||||
buf.append( "\n" );
|
||||
}
|
||||
content = buf.toString();
|
||||
saved = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void save()
|
||||
{
|
||||
File file = new File( getFileName() );
|
||||
try {
|
||||
PrintWriter out = new PrintWriter( new FileOutputStream( file ) );
|
||||
out.print( content );
|
||||
out.flush();
|
||||
out.close();
|
||||
saved = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public String getMessages() {
|
||||
String message = "";
|
||||
if( action != null ) {
|
||||
if( lastSerial != null && serial != null && serial.compareTo( lastSerial ) == 0 ) {
|
||||
if( action.compareToIgnoreCase( "save") == 0 ) {
|
||||
save();
|
||||
message = "Subscriptions saved.";
|
||||
}
|
||||
else if( action.compareToIgnoreCase( "reload") == 0 ) {
|
||||
reload();
|
||||
message = "Subscriptions reloaded.";
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = "Invalid nonce. Are you being spoofed?";
|
||||
}
|
||||
}
|
||||
if( message.length() > 0 )
|
||||
message = "<p class=\"messages\">" + message + "</p>";
|
||||
return message;
|
||||
}
|
||||
public String getSerial()
|
||||
{
|
||||
lastSerial = "" + Math.random();
|
||||
action = null;
|
||||
return lastSerial;
|
||||
}
|
||||
public void setSerial(String serial ) {
|
||||
this.serial = serial;
|
||||
}
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
this.saved = false;
|
||||
|
||||
/*
|
||||
* as this is a property file we need a newline at the end of the last line!
|
||||
*/
|
||||
if( ! this.content.endsWith( "\n" ) ) {
|
||||
this.content += "\n";
|
||||
}
|
||||
}
|
||||
public String getContent()
|
||||
{
|
||||
if( content != null )
|
||||
return content;
|
||||
|
||||
reload();
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
39
apps/susidns/src/java/src/i2p/susi/dns/VersionBean.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.4 $
|
||||
*/
|
||||
|
||||
package i2p.susi.dns;
|
||||
|
||||
public class VersionBean {
|
||||
|
||||
private static String version = "0.4";
|
||||
private static String url = "http://susi.i2p/?i2paddresshelper=T2DU1KAz3meB0B53U8Y06-I7vHR7XmC0qXAJfLW6b-1L1FVKoySRZz4xazHAwyv2xtRpvKrv6ukLm1tThEW0zQWtZPtX8G6KkzMibD8t7IS~4yw-9VkBtUydyYfsX08AK3v~-egSW8HCXTdyIJVtrETJb337VDUHW-7D4L1JLbwSH4if2ooks6yFTrljK5aVMi-16dZOVvmoyJc3jBqSdK6kraO4gW5-vHTmbLwL498p9nug1KOg1DqgN2GeU5X1QlVrlpFb~IIfdP~O8NT7u-LAjW3jSJsMbLDHMSYTIhC7xmJIiBoi-qk8p6TLynAmvJ7HRvbx4N1EB-uJHyD16wsZkkHyEOfmXbj0ZqLyKEGb3thPwCz-M9v~c2Qt3WbwjXJAtHpjlHkdJ4Fg91cX2oak~JoapnPf6Syw8hko5syf6VVoCYLnrrYyM8oGl8mLclHkj~VCidQNqMSM74IhrHfK6HmRikqtZBexb5M6wfMTTqBvaHURdD21GOpFKYBUAAAA";
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
}
|
168
apps/susidns/src/jsp/addressbook.jsp
Normal file
@ -0,0 +1,168 @@
|
||||
<%
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<jsp:useBean id="version" class="i2p.susi.dns.VersionBean" scope="application" />
|
||||
<jsp:useBean id="book" class="i2p.susi.dns.AddressbookBean" scope="session" />
|
||||
<jsp:setProperty name="book" property="*" />
|
||||
<jsp:setProperty name="book" property="resetDeletionMarks" value="1"/>
|
||||
<c:forEach items="${paramValues.checked}" var="checked">
|
||||
<jsp:setProperty name="book" property="markedForDeletion" value="${checked}"/>
|
||||
</c:forEach>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>${book.book} addressbook - susidns v${version.version}</title>
|
||||
<link rel="stylesheet" type="text/css" href="css.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="logo">
|
||||
<img src="images/logo.png" alt="susidns logo" border="0"/>
|
||||
</div>
|
||||
|
||||
<div id="navi">
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="headline">
|
||||
<h3>${book.book} addressbook at ${book.fileName}</h3>
|
||||
</div>
|
||||
|
||||
<div id="messages">${book.messages}</div>
|
||||
|
||||
<div id="filter">
|
||||
<p>Filter: <a href="addressbook.jsp?filter=a">a</a>
|
||||
<a href="addressbook.jsp?filter=b">b</a>
|
||||
<a href="addressbook.jsp?filter=c">c</a>
|
||||
<a href="addressbook.jsp?filter=d">d</a>
|
||||
<a href="addressbook.jsp?filter=e">e</a>
|
||||
<a href="addressbook.jsp?filter=f">f</a>
|
||||
<a href="addressbook.jsp?filter=g">g</a>
|
||||
<a href="addressbook.jsp?filter=h">h</a>
|
||||
<a href="addressbook.jsp?filter=i">i</a>
|
||||
<a href="addressbook.jsp?filter=j">j</a>
|
||||
<a href="addressbook.jsp?filter=k">k</a>
|
||||
<a href="addressbook.jsp?filter=l">l</a>
|
||||
<a href="addressbook.jsp?filter=m">m</a>
|
||||
<a href="addressbook.jsp?filter=n">n</a>
|
||||
<a href="addressbook.jsp?filter=o">o</a>
|
||||
<a href="addressbook.jsp?filter=p">p</a>
|
||||
<a href="addressbook.jsp?filter=q">q</a>
|
||||
<a href="addressbook.jsp?filter=r">r</a>
|
||||
<a href="addressbook.jsp?filter=s">s</a>
|
||||
<a href="addressbook.jsp?filter=t">t</a>
|
||||
<a href="addressbook.jsp?filter=u">u</a>
|
||||
<a href="addressbook.jsp?filter=v">v</a>
|
||||
<a href="addressbook.jsp?filter=w">w</a>
|
||||
<a href="addressbook.jsp?filter=x">x</a>
|
||||
<a href="addressbook.jsp?filter=y">y</a>
|
||||
<a href="addressbook.jsp?filter=z">z</a>
|
||||
<a href="addressbook.jsp?filter=0-9">0-9</a>
|
||||
<a href="addressbook.jsp?filter=none">all</a></p>
|
||||
<c:if test="${book.hasFilter}">
|
||||
<p>Current filter: ${book.filter}</p>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<div id="search">
|
||||
<table><tr>
|
||||
<td class="search">Search: <input type="text" name="search" value="${book.search}" size="20" /></td>
|
||||
<td class="search"><input type="image" src="images/search.png" name="submitsearch" value="search" alt="Search" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<input type="hidden" name="serial" value="${book.serial}"/>
|
||||
|
||||
<c:if test="${book.notEmpty}">
|
||||
|
||||
<div id="book">
|
||||
<jsp:setProperty name="book" property="trClass" value="0" />
|
||||
<table class="book" cellspacing="0" cellpadding="5">
|
||||
<tr class="head">
|
||||
|
||||
<c:if test="${book.master || book.router}">
|
||||
<th> </th>
|
||||
</c:if>
|
||||
|
||||
<th>Name</th>
|
||||
<th>Destination</th>
|
||||
</tr>
|
||||
<c:forEach items="${book.entries}" var="addr">
|
||||
<tr class="list${book.trClass}">
|
||||
<c:if test="${book.master || book.router}">
|
||||
<td class="checkbox"><input type="checkbox" name="checked" value="${addr.name}" alt="Mark for deletion"></td>
|
||||
</c:if>
|
||||
<td class="names"><a href="http://${addr.name}/">${addr.name}</a> -
|
||||
<span class="addrhlpr"><a href="http://${addr.name}/?i2paddresshelper=${addr.destination}">(addrhlpr)</a></span>
|
||||
</td>
|
||||
<td class="destinations"><input type="text" name="dest_${addr.name}" value="${addr.destination}" size="20"></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<c:if test="${book.master || book.router}">
|
||||
<div id="buttons">
|
||||
<p class="buttons"><input type="image" name="action" value="delete" src="images/delete.png" alt="Delete checked" />
|
||||
</p>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
</c:if>
|
||||
|
||||
<c:if test="${book.isEmpty}">
|
||||
<div id="book">
|
||||
<p class="book">The ${book.book} addressbook is empty.</p>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<div id="add">
|
||||
<p class="add">
|
||||
<h3>Add new destination:</h3>
|
||||
Hostname: <input type="text" name="hostname" value="" size="20"> Destination: <input type="text" name="destination" value="" size="20"><br/>
|
||||
<input type="image" name="action" value="add" src="images/add.png" alt="Add destination" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<div id="footer">
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
96
apps/susidns/src/jsp/config.jsp
Normal file
@ -0,0 +1,96 @@
|
||||
<%
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.14 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<jsp:useBean id="version" class="i2p.susi.dns.VersionBean" scope="application"/>
|
||||
<jsp:useBean id="cfg" class="i2p.susi.dns.ConfigBean" scope="session"/>
|
||||
<jsp:setProperty name="cfg" property="*" />
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>configuration - susidns v${version.version}</title>
|
||||
<link rel="stylesheet" type="text/css" href="css.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="logo">
|
||||
<img src="images/logo.png" alt="susidns logo" border="0"/>
|
||||
</div>
|
||||
<div id="navi">
|
||||
<p>
|
||||
addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="headline">
|
||||
<h3>${cfg.fileName}</h3>
|
||||
</div>
|
||||
<div id="messages">${cfg.messages}</div>
|
||||
<form method="POST" action="config.jsp">
|
||||
<div id="config">
|
||||
<input type="hidden" name="serial" value="${cfg.serial}" />
|
||||
<textarea name="config" rows="10" cols="80">${cfg.config}</textarea>
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<input type="image" src="images/save.png" name="action" value="save" alt="Save Config"/>
|
||||
<input type="image" src="images/reload.png" name="action" value="reload" alt="Reload Config"/>
|
||||
</div>
|
||||
</form>
|
||||
<div id="help">
|
||||
<h3>Hints</h3>
|
||||
<ol>
|
||||
<li>All file or directory paths here are relative to the addressbooks working directory, which normally
|
||||
is located at $I2P/addressbook/.</li>
|
||||
<li>If you want to manually add lines to an addressbook, add them to the master addressbook. The router
|
||||
addressbook and the published addressbook are overwritten by the addressbook application.</li>
|
||||
<li><b>Important:</b>When you publish your addressbook, <b>ALL</b> destinations appear there, even those
|
||||
from your master addressbook. Unfortunately the master addressbook points to your userhosts.txt, which was
|
||||
used for private destinations before. So if you want to keep the destinations in your userhosts.txt secret,
|
||||
please change the master addressbook to a different file before turning on addressbook publishing.</li>
|
||||
</ol>
|
||||
<h3>Options</h3>
|
||||
<ul>
|
||||
<li><b>subscriptions</b> - file containing the list of subscriptions URLs (no need to change)</li>
|
||||
<li><b>update_delay</b> - update interval in hours (no need to change)</li>
|
||||
<li><b>published_addressbook</b> - your public hosts.txt file (choose a path within your webserver document root)</li>
|
||||
<li><b>router_addressbook</b> - your hosts.txt (no need to change)</li>
|
||||
<li><b>master_addressbook</b> - your personal addressbook, it gets never overwritten by the addressbook</li>
|
||||
<li><b>proxy_port</b> - http port for your eepProxy (no need to change)</li>
|
||||
<li><b>proxy_host</b> - hostname for your eepProxy (no need to change)</li>
|
||||
<li><b>should_publish</b> - true/false whether to write the published addressbook</li>
|
||||
<li><b>etags</b> - file containing the etags header from the fetched subscription URLs (no need to change)</li>
|
||||
<li><b>last_modified</b> - file containing the modification timestamp for each fetched subscription URL (no need to change)</li>
|
||||
<li><b>log</b> - file to log activity to (change to /dev/null if you like)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005 </p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
80
apps/susidns/src/jsp/index.jsp
Normal file
@ -0,0 +1,80 @@
|
||||
<%
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.1 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<jsp:useBean id="version" class="i2p.susi.dns.VersionBean" scope="application" />
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>introduction - susidns v${version.version}</title>
|
||||
<link rel="stylesheet" type="text/css" href="css.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="logo">
|
||||
<img src="images/logo.png" alt="susidns logo" border="0"/>
|
||||
</div>
|
||||
|
||||
<div id="navi">
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h3>Huh? what addressbook?</h3>
|
||||
<p>
|
||||
The addressbook application is part of your i2p installation. It regularly updates your hosts.txt file
|
||||
from distributed sources. It keeps your hosts.txt up to date, so it automatically contains all new
|
||||
eepsites announced on <a href="http://orion.i2p">orion</a>
|
||||
or in the <a href="http://forum.i2p/viewforum.php?f=16">forum</a>.
|
||||
</p>
|
||||
<p>
|
||||
(To speak the truth: In its default configuration the addressbook does not poll
|
||||
orion, but dev.i2p only. Subscribing to <a href="http://orion.i2p">orion</a> is an easy task,
|
||||
just add <a href="http://orion.i2p/hosts.txt">http://orion.i2p/hosts.txt</a> to your <a href="subscriptions.jsp">subscriptions</a> file.)
|
||||
</p>
|
||||
<p>If you have questions about naming in i2p, there is an excellent <a href="http://forum.i2p.net/viewtopic.php?t=134">introduction</a>
|
||||
from duck in the forum.</p>
|
||||
<h3>How does the addressbook work?</h3>
|
||||
<p>The addressbook application regularly (normally once per hour) polls your subscriptions and merges their content
|
||||
into your so called router addressbook (normally your plain hosts.txt). Then it merges your so called master addressbook (normally
|
||||
your userhosts.txt) into the router addressbook as well. If configured the router addressbook is now written to the so published addressbook,
|
||||
which is a publicly available copy of your hosts.txt somewhere in your eepsites document root. (Yes, this means that, with activated publication,
|
||||
your once private keys from userhosts.txt now are publicly available for everybody.)
|
||||
</p>
|
||||
<p><img src="images/how.png" border="0" alt="addressbook working scheme"/></p>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
78
apps/susidns/src/jsp/subscriptions.jsp
Normal file
@ -0,0 +1,78 @@
|
||||
<%
|
||||
/*
|
||||
* Created on Sep 02, 2005
|
||||
*
|
||||
* This file is part of susidns project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.7 $
|
||||
*/
|
||||
%>
|
||||
<%@ page contentType="text/html"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<jsp:useBean id="version" class="i2p.susi.dns.VersionBean" scope="application" />
|
||||
<jsp:useBean id="subs" class="i2p.susi.dns.SubscriptionsBean" scope="session" />
|
||||
<jsp:setProperty name="subs" property="*" />
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>subscriptions - susidns v${version.version}</title>
|
||||
<link rel="stylesheet" type="text/css" href="css.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="logo">
|
||||
<img src="images/logo.png" alt="susidns logo" border="0"/>
|
||||
</div>
|
||||
<div id="navi">
|
||||
<p>addressbooks
|
||||
<a href="addressbook.jsp?book=master">master</a> |
|
||||
<a href="addressbook.jsp?book=router">router</a> |
|
||||
<a href="addressbook.jsp?book=published">published</a> *
|
||||
<a href="subscriptions.jsp">subscriptions</a> *
|
||||
<a href="config.jsp">configuration</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="headline">
|
||||
<h3>${subs.fileName}</h3>
|
||||
</div>
|
||||
<div id="messages">${subs.messages}</div>
|
||||
<form method="POST" action="subscriptions.jsp">
|
||||
<div id="content">
|
||||
<input type="hidden" name="serial" value="${subs.serial}" />
|
||||
<textarea name="content" rows="10" cols="80">${subs.content}</textarea>
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<input type="image" src="images/save.png" name="action" value="save" alt="Save Subscriptions" />
|
||||
<input type="image" src="images/reload.png" name="action" value="reload" alt="Reload Subscriptions" />
|
||||
</div>
|
||||
</form>
|
||||
<div id="help">
|
||||
<h3>Explanation</h3>
|
||||
<p class="help">
|
||||
The subscription file contains a list of (i2p) URLs. The addressbook application
|
||||
regularly (once per hour) checks this list for new eepsites. Those URLs simply contain the published hosts.txt
|
||||
file of other people. Default subscription is the hosts.txt from dev.i2p. The most
|
||||
popular collaboration site for eepsite is orion.i2p. So its a good idea to add http://orion.i2p/hosts.txt
|
||||
as a 2nd subscription.
|
||||
</p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -90,6 +90,12 @@ public class Archive {
|
||||
}
|
||||
|
||||
public String getDefaultSelector() { return _defaultSelector; }
|
||||
public void setDefaultSelector(String sel) {
|
||||
if (sel == null)
|
||||
_defaultSelector = "";
|
||||
else
|
||||
_defaultSelector = sel;
|
||||
}
|
||||
|
||||
public BlogInfo getBlogInfo(BlogURI uri) {
|
||||
if (uri == null) return null;
|
||||
@ -209,15 +215,19 @@ public class Archive {
|
||||
|
||||
private EntryContainer getCachedEntry(File entryDir) {
|
||||
try {
|
||||
return new CachedEntry(entryDir);
|
||||
CachedEntry ce = new CachedEntry(entryDir);
|
||||
if (ce.isValid())
|
||||
return ce;
|
||||
return null;
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
File files[] = entryDir.listFiles();
|
||||
for (int i = 0; i < files.length; i++)
|
||||
files[i].delete();
|
||||
entryDir.delete();
|
||||
return null;
|
||||
}
|
||||
|
||||
File files[] = entryDir.listFiles();
|
||||
for (int i = 0; i < files.length; i++)
|
||||
files[i].delete();
|
||||
entryDir.delete();
|
||||
return null;
|
||||
}
|
||||
|
||||
public EntryContainer getEntry(BlogURI uri) { return getEntry(uri, null); }
|
||||
|
@ -16,7 +16,7 @@ class ArchiveIndexer {
|
||||
private static final int RECENT_ENTRY_COUNT = 10;
|
||||
|
||||
public static ArchiveIndex index(I2PAppContext ctx, Archive source) {
|
||||
LocalArchiveIndex rv = new LocalArchiveIndex();
|
||||
LocalArchiveIndex rv = new LocalArchiveIndex(ctx);
|
||||
rv.setGeneratedOn(ctx.clock().now());
|
||||
|
||||
File rootDir = source.getArchiveDir();
|
||||
@ -54,7 +54,7 @@ class ArchiveIndexer {
|
||||
long totalSize = 0;
|
||||
int newBlogs = 0;
|
||||
|
||||
SMLParser parser = new SMLParser();
|
||||
SMLParser parser = new SMLParser(ctx);
|
||||
|
||||
for (int i = 0; i < blogs.size(); i++) {
|
||||
BlogInfo cur = (BlogInfo)blogs.get(i);
|
||||
@ -158,7 +158,7 @@ class ArchiveIndexer {
|
||||
_headers.setProperty(header, value);
|
||||
}
|
||||
|
||||
public void receiveAddress(String name, String schema, String location, String anchorText) {}
|
||||
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() {}
|
||||
|
@ -4,6 +4,8 @@ import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetName;
|
||||
import net.i2p.client.naming.PetNameDB;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
@ -63,8 +65,9 @@ public class BlogManager {
|
||||
_archive.regenerateIndex();
|
||||
}
|
||||
|
||||
private File getConfigFile() { return new File(_rootDir, "syndie.config"); }
|
||||
private void readConfig() {
|
||||
File config = new File(_rootDir, "syndie.config");
|
||||
File config = getConfigFile();
|
||||
if (config.exists()) {
|
||||
try {
|
||||
Properties p = new Properties();
|
||||
@ -72,10 +75,13 @@ public class BlogManager {
|
||||
for (Iterator iter = p.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
System.setProperty(key, p.getProperty(key));
|
||||
System.out.println("Read config prop [" + key + "] = [" + p.getProperty(key) + "]");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.out.println("Config doesn't exist: " + config.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,8 +143,30 @@ public class BlogManager {
|
||||
return info;
|
||||
}
|
||||
|
||||
public boolean updateMetadata(User user, Hash blog, Properties opts) {
|
||||
if (!user.getAuthenticated()) return false;
|
||||
BlogInfo oldInfo = getArchive().getBlogInfo(blog);
|
||||
if (oldInfo == null) return false;
|
||||
if (!user.getBlog().equals(oldInfo.getKey().calculateHash())) return false;
|
||||
int oldEdition = 0;
|
||||
try {
|
||||
String ed = oldInfo.getProperty("Edition");
|
||||
if (ed != null)
|
||||
oldEdition = Integer.parseInt(ed);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
opts.setProperty("Edition", oldEdition + 1 + "");
|
||||
BlogInfo info = new BlogInfo(oldInfo.getKey(), oldInfo.getPosters(), opts);
|
||||
SigningPrivateKey key = getMyPrivateKey(oldInfo);
|
||||
info.sign(_context, key);
|
||||
getArchive().storeBlogInfo(info);
|
||||
user.setLastMetaEntry(oldEdition+1);
|
||||
saveUser(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Archive getArchive() { return _archive; }
|
||||
public File getTempDir() { return _tempDir; }
|
||||
public File getRootDir() { return _rootDir; }
|
||||
|
||||
public List listMyBlogs() {
|
||||
File files[] = _privKeyDir.listFiles();
|
||||
@ -181,6 +209,7 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
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));
|
||||
Hash passHash = _context.sha().calculateHash(DataHelper.getUTF8(pass));
|
||||
File userFile = new File(_userDir, Base64.encode(userHash.getData()));
|
||||
@ -203,20 +232,124 @@ public class BlogManager {
|
||||
return user.login(login, pass, props);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return "Error logging in - corrupt userfile";
|
||||
return "<span class=\"b_loginMsgErr\">Error logging in - corrupt userfile</span>";
|
||||
}
|
||||
} else {
|
||||
return "User does not exist";
|
||||
return "<span class=\"b_loginMsgErr\">User does not exist</span>";
|
||||
}
|
||||
}
|
||||
|
||||
/** hash of the password required to register and create a new blog (null means no password required) */
|
||||
public String getRegistrationPassword() {
|
||||
public String getRegistrationPasswordHash() {
|
||||
String pass = _context.getProperty("syndie.registrationPassword");
|
||||
if ( (pass == null) || (pass.trim().length() <= 0) ) return null;
|
||||
return pass;
|
||||
}
|
||||
|
||||
/** Password required to access the remote syndication functinoality (null means no password required) */
|
||||
public String getRemotePasswordHash() {
|
||||
String pass = _context.getProperty("syndie.remotePassword");
|
||||
|
||||
System.out.println("Remote password? [" + pass + "]");
|
||||
if ( (pass == null) || (pass.trim().length() <= 0) ) return null;
|
||||
return pass;
|
||||
}
|
||||
public String getAdminPasswordHash() {
|
||||
String pass = _context.getProperty("syndie.adminPassword");
|
||||
if ( (pass == null) || (pass.trim().length() <= 0) ) return "";
|
||||
return pass;
|
||||
}
|
||||
|
||||
public boolean isConfigured() {
|
||||
File cfg = getConfigFile();
|
||||
return (cfg.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
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 boolean authorizeAdmin(String pass) {
|
||||
if (isSingleUser()) return true;
|
||||
String admin = getAdminPasswordHash();
|
||||
if ( (admin == null) || (admin.trim().length() <= 0) )
|
||||
return false;
|
||||
String hash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(pass.trim())).getData());
|
||||
return (hash.equals(admin));
|
||||
}
|
||||
public boolean authorizeRemote(String pass) {
|
||||
if (isSingleUser()) return true;
|
||||
String rem = getRemotePasswordHash();
|
||||
if ( (rem == null) || (rem.trim().length() <= 0) )
|
||||
return false;
|
||||
String hash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(pass.trim())).getData());
|
||||
return (hash.equals(rem));
|
||||
}
|
||||
public boolean authorizeRemote(User user) {
|
||||
if (isSingleUser()) return true;
|
||||
return (user.getAuthenticated() && user.getAllowAccessRemote());
|
||||
}
|
||||
|
||||
public void configure(String registrationPassword, String remotePassword, String adminPass, String defaultSelector,
|
||||
String defaultProxyHost, int defaultProxyPort, boolean isSingleUser, Properties opts) {
|
||||
File cfg = getConfigFile();
|
||||
Writer out = null;
|
||||
try {
|
||||
out = new OutputStreamWriter(new FileOutputStream(cfg), "UTF-8");
|
||||
if (registrationPassword != null)
|
||||
out.write("syndie.registrationPassword="+Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(registrationPassword.trim())).getData()) + "\n");
|
||||
if (remotePassword != null)
|
||||
out.write("syndie.remotePassword="+Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(remotePassword.trim())).getData()) + "\n");
|
||||
if (adminPass != null)
|
||||
out.write("syndie.adminPassword="+Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(adminPass.trim())).getData()) + "\n");
|
||||
if (defaultSelector != null)
|
||||
out.write("syndie.defaultSelector="+defaultSelector.trim() + "\n");
|
||||
if (defaultProxyHost != null)
|
||||
out.write("syndie.defaultProxyHost="+defaultProxyHost.trim() + "\n");
|
||||
if (defaultProxyPort > 0)
|
||||
out.write("syndie.defaultProxyPort="+defaultProxyPort + "\n");
|
||||
out.write("syndie.singleUser=" + isSingleUser + "\n");
|
||||
if (opts != null) {
|
||||
for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = opts.getProperty(key);
|
||||
out.write(key.trim() + "=" + val.trim() + "\n");
|
||||
}
|
||||
}
|
||||
_archive.setDefaultSelector(defaultSelector);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
readConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public String authorizeRemoteAccess(User user, String password) {
|
||||
if (!user.getAuthenticated()) return "<span class=\"b_remoteMsgErr\">Not logged in</span>";
|
||||
String remPass = getRemotePasswordHash();
|
||||
if (remPass == null)
|
||||
return "<span class=\"b_remoteMsgErr\">Remote access password not configured - please <a href=\"admin.jsp\">specify</a> a remote " +
|
||||
"archive password</span>";
|
||||
|
||||
if (authorizeRemote(password)) {
|
||||
user.setAllowAccessRemote(true);
|
||||
saveUser(user);
|
||||
return "<span class=\"b_remoteMsgOk\">Remote access authorized</span>";
|
||||
} else {
|
||||
return "<span class=\"b_remoteMsgErr\">Remote access denied</span>";
|
||||
}
|
||||
}
|
||||
|
||||
public void saveUser(User user) {
|
||||
if (!user.getAuthenticated()) return;
|
||||
String userHash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(user.getUsername())).getData());
|
||||
@ -225,6 +358,7 @@ public class BlogManager {
|
||||
try {
|
||||
out = new FileOutputStream(userFile);
|
||||
out.write(DataHelper.getUTF8(user.export()));
|
||||
user.getPetNameDB().store(user.getAddressbookLocation());
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
@ -232,21 +366,20 @@ public class BlogManager {
|
||||
}
|
||||
}
|
||||
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 + "]");
|
||||
System.err.println("reference bad string: [" + EncodingTestGenerator.TEST_STRING + "]");
|
||||
String hashedRegistrationPassword = getRegistrationPassword();
|
||||
if (hashedRegistrationPassword != null) {
|
||||
System.err.println("Register [" + login + "] pass [" + password + "] name [" + blogName + "] descr [" + blogDescription + "] contact [" + contactURL + "] regPass [" + registrationPassword + "]");
|
||||
String hashedRegistrationPassword = getRegistrationPasswordHash();
|
||||
if ( (hashedRegistrationPassword != null) && (!isSingleUser()) ) {
|
||||
try {
|
||||
if (!hashedRegistrationPassword.equals(Base64.encode(_context.sha().calculateHash(registrationPassword.getBytes("UTF-8")).getData())))
|
||||
return "Invalid registration password";
|
||||
return "<span class=\"b_regMsgErr\">Invalid registration password</span>";
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
return "Error registering";
|
||||
return "<span class=\"b_regMsgErr\">Error registering</span>";
|
||||
}
|
||||
}
|
||||
String userHash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(login)).getData());
|
||||
File userFile = new File(_userDir, userHash);
|
||||
if (userFile.exists()) {
|
||||
return "Cannot register the login " + login + ": it already exists";
|
||||
return "<span class=\"b_regMsgErr\">Cannot register the login " + login + ": it already exists</span>";
|
||||
} else {
|
||||
BlogInfo info = createBlog(blogName, blogDescription, contactURL, null);
|
||||
String hashedPassword = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(password)).getData());
|
||||
@ -264,7 +397,7 @@ public class BlogManager {
|
||||
bw.flush();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return "Internal error registering - " + ioe.getMessage();
|
||||
return "<span class=\"b_regMsgErr\">Internal error registering - " + ioe.getMessage() + "</span>";
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
@ -273,6 +406,29 @@ public class BlogManager {
|
||||
return loginResult;
|
||||
}
|
||||
}
|
||||
|
||||
public String exportHosts(User user) {
|
||||
if (!user.getAuthenticated() || !user.getAllowAccessRemote())
|
||||
return "<span class=\"b_addrMsgErr\">Not authorized to export the hosts</span>";
|
||||
PetNameDB userDb = user.getPetNameDB();
|
||||
PetNameDB routerDb = _context.petnameDb();
|
||||
// horribly inefficient...
|
||||
for (Iterator names = userDb.getNames().iterator(); names.hasNext();) {
|
||||
PetName pn = userDb.get((String)names.next());
|
||||
if (pn == null) continue;
|
||||
Destination existing = _context.namingService().lookup(pn.getName());
|
||||
if (existing == null && pn.getNetwork().equalsIgnoreCase("i2p")) {
|
||||
routerDb.set(pn.getName(), pn);
|
||||
try {
|
||||
routerDb.store();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return "<span class=\"b_addrMsgErr\">Error exporting the hosts: " + ioe.getMessage() + "</span>";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<span class=\"b_addrMsgOk\">Hosts exported</span>";
|
||||
}
|
||||
|
||||
public BlogURI createBlogEntry(User user, String subject, String tags, String entryHeaders, String sml) {
|
||||
return createBlogEntry(user, subject, tags, entryHeaders, sml, null, null, null);
|
||||
@ -397,30 +553,27 @@ public class BlogManager {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String addAddress(User user, String name, String location, String schema) {
|
||||
if (!user.getAuthenticated()) return "Not logged in";
|
||||
|
||||
public String addAddress(User user, String name, String protocol, String location, String schema) {
|
||||
if (!user.getAuthenticated()) return "<span class=\"b_addrMsgErr\">Not logged in</span>";
|
||||
boolean ok = validateAddressName(name);
|
||||
if (!ok) return "Invalid name: " + HTMLRenderer.sanitizeString(name);
|
||||
if (!ok) return "<span class=\"b_addrMsgErr\">Invalid name: " + HTMLRenderer.sanitizeString(name) + "</span>";
|
||||
ok = validateAddressLocation(location);
|
||||
if (!ok) return "Invalid location: " + HTMLRenderer.sanitizeString(location);
|
||||
if (!validateAddressSchema(schema)) return "Unsupported schema: " + HTMLRenderer.sanitizeString(schema);
|
||||
if (!ok) return "<span class=\"b_addrMsgErr\">Invalid location: " + HTMLRenderer.sanitizeString(location) + "</span>";
|
||||
if (!validateAddressSchema(schema)) return "<span class=\"b_addrMsgErr\">Unsupported schema: " + HTMLRenderer.sanitizeString(schema) + "</span>";
|
||||
// no need to quote user/location further, as they've been sanitized
|
||||
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
File userHostsFile = new File(user.getAddressbookLocation());
|
||||
Properties knownHosts = getKnownHosts(user, true);
|
||||
if (knownHosts.containsKey(name)) return "Name is already in use";
|
||||
PetNameDB names = user.getPetNameDB();
|
||||
if (names.exists(name))
|
||||
return "<span class=\"b_addrMsgErr\">Name is already in use</span>";
|
||||
PetName pn = new PetName(name, schema, protocol, location);
|
||||
names.set(name, pn);
|
||||
|
||||
out = new FileOutputStream(userHostsFile, true);
|
||||
out.write(DataHelper.getUTF8(name + "=" + location + '\n'));
|
||||
return "Address " + name + " written to your hosts file (" + userHostsFile.getName() + ")";
|
||||
try {
|
||||
names.store(user.getAddressbookLocation());
|
||||
return "<span class=\"b_addrMsgOk\">Address " + name + " written to your addressbook</span>";
|
||||
} catch (IOException ioe) {
|
||||
return "Error writing out host entry: " + ioe.getMessage();
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
return "<span class=\"b_addrMsgErr\">Error writing out the name: " + ioe.getMessage() + "</span>";
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +597,7 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
private boolean validateAddressName(String name) {
|
||||
if ( (name == null) || (name.trim().length() <= 0) || (!name.endsWith(".i2p")) ) return false;
|
||||
if ( (name == null) || (name.trim().length() <= 0) ) return false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (!Character.isLetterOrDigit(c) && ('.' != c) && ('-' != c) && ('_' != c) )
|
||||
@ -455,18 +608,27 @@ public class BlogManager {
|
||||
|
||||
private boolean validateAddressLocation(String location) {
|
||||
if ( (location == null) || (location.trim().length() <= 0) ) return false;
|
||||
try {
|
||||
Destination d = new Destination(location);
|
||||
return (d.getPublicKey() != null);
|
||||
} catch (DataFormatException dfe) {
|
||||
dfe.printStackTrace();
|
||||
return false;
|
||||
if (false) {
|
||||
try {
|
||||
Destination d = new Destination(location);
|
||||
return (d.getPublicKey() != null);
|
||||
} catch (DataFormatException dfe) {
|
||||
dfe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// not everything is an i2p destination...
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateAddressSchema(String schema) {
|
||||
if ( (schema == null) || (schema.trim().length() <= 0) ) return false;
|
||||
return "eep".equals(schema) || "i2p".equals(schema);
|
||||
if (true) {
|
||||
return true;
|
||||
} else {
|
||||
return "eep".equals(schema) || "i2p".equals(schema);
|
||||
}
|
||||
}
|
||||
|
||||
private final SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.UK);
|
||||
|
@ -111,7 +111,7 @@ public class CLI {
|
||||
entryKey = new SessionKey(Base64.decode(args[5]));
|
||||
EntryContainer entry = mgr.getArchive().getEntry(new BlogURI(new Hash(Base64.decode(args[2])), id), entryKey);
|
||||
if (entry != null) {
|
||||
HTMLRenderer renderer = new HTMLRenderer();
|
||||
HTMLRenderer renderer = new HTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
boolean summaryOnly = "true".equalsIgnoreCase(args[5]);
|
||||
boolean showImages = "true".equalsIgnoreCase(args[6]);
|
||||
try {
|
||||
|
@ -28,6 +28,10 @@ class CachedEntry extends EntryContainer {
|
||||
_attachments = null;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return (_entry != null) && (_blog != null);
|
||||
}
|
||||
|
||||
// always available, loaded from meta
|
||||
public int getFormat() { return _format; }
|
||||
public BlogURI getURI() { return _blog; }
|
||||
@ -70,7 +74,7 @@ class CachedEntry extends EntryContainer {
|
||||
}
|
||||
|
||||
// now the actual lazy loading code
|
||||
private void importMeta() {
|
||||
private void importMeta() throws IOException {
|
||||
Properties meta = readProps(new File(_entryDir, EntryExtractor.META));
|
||||
_format = getInt(meta, "format");
|
||||
_size = getInt(meta, "size");
|
||||
@ -78,8 +82,14 @@ class CachedEntry extends EntryContainer {
|
||||
}
|
||||
|
||||
private Properties importHeaders() {
|
||||
if (_headers == null)
|
||||
_headers = readProps(new File(_entryDir, EntryExtractor.HEADERS));
|
||||
if (_headers == null) {
|
||||
try {
|
||||
_headers = readProps(new File(_entryDir, EntryExtractor.HEADERS));
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
_headers = new Properties();
|
||||
}
|
||||
}
|
||||
return _headers;
|
||||
}
|
||||
|
||||
@ -103,7 +113,7 @@ class CachedEntry extends EntryContainer {
|
||||
return;
|
||||
}
|
||||
|
||||
private static Properties readProps(File propsFile) {
|
||||
private static Properties readProps(File propsFile) throws IOException {
|
||||
Properties rv = new Properties();
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
@ -114,8 +124,6 @@ class CachedEntry extends EntryContainer {
|
||||
if ( (split <= 0) || (split >= line.length()) ) continue;
|
||||
rv.setProperty(line.substring(0, split).trim(), line.substring(split+1).trim());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
@ -222,15 +230,20 @@ class CachedEntry extends EntryContainer {
|
||||
|
||||
private void importAttachmentHeaders() {
|
||||
if (_attachmentHeaders == null) {
|
||||
Properties props = readProps(_metaFile);
|
||||
String sz = (String)props.remove(EntryExtractor.ATTACHMENT_DATA_SIZE);
|
||||
if (sz != null) {
|
||||
try {
|
||||
_dataSize = Integer.parseInt(sz);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
try {
|
||||
Properties props = readProps(_metaFile);
|
||||
String sz = (String)props.remove(EntryExtractor.ATTACHMENT_DATA_SIZE);
|
||||
if (sz != null) {
|
||||
try {
|
||||
_dataSize = Integer.parseInt(sz);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
_attachmentHeaders = props;
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
_attachmentHeaders = new Properties();
|
||||
}
|
||||
|
||||
_attachmentHeaders = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetNameDB;
|
||||
import net.i2p.data.*;
|
||||
|
||||
/**
|
||||
@ -36,6 +38,7 @@ public class User {
|
||||
private int _webProxyPort;
|
||||
private String _torProxyHost;
|
||||
private int _torProxyPort;
|
||||
private PetNameDB _petnames;
|
||||
|
||||
public User() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
@ -51,7 +54,7 @@ public class User {
|
||||
_shitlistedBlogs = new ArrayList();
|
||||
_defaultSelector = null;
|
||||
_addressbookLocation = "userhosts.txt";
|
||||
_showImagesByDefault = false;
|
||||
_showImagesByDefault = true;
|
||||
_showExpandedByDefault = false;
|
||||
_allowAccessRemote = false;
|
||||
_eepProxyHost = null;
|
||||
@ -62,6 +65,7 @@ public class User {
|
||||
_torProxyPort = -1;
|
||||
_lastLogin = -1;
|
||||
_lastMetaEntry = 0;
|
||||
_petnames = new PetNameDB();
|
||||
}
|
||||
|
||||
public boolean getAuthenticated() { return _authenticated; }
|
||||
@ -92,8 +96,11 @@ public class User {
|
||||
public String getTorProxyHost() { return _torProxyHost; }
|
||||
public int getTorProxyPort() { return _torProxyPort; }
|
||||
|
||||
public PetNameDB getPetNameDB() { return _petnames; }
|
||||
|
||||
public void invalidate() {
|
||||
BlogManager.instance().saveUser(this);
|
||||
if (_authenticated)
|
||||
BlogManager.instance().saveUser(this);
|
||||
init();
|
||||
}
|
||||
|
||||
@ -102,7 +109,7 @@ public class User {
|
||||
String hpass = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(pass)).getData());
|
||||
if (!hpass.equals(expectedPass)) {
|
||||
_authenticated = false;
|
||||
return "Incorrect password";
|
||||
return "<span class=\"b_loginMsgErr\">Incorrect password</span>";
|
||||
}
|
||||
|
||||
_username = login;
|
||||
@ -156,10 +163,16 @@ public class User {
|
||||
}
|
||||
|
||||
String addr = props.getProperty("addressbook", "userhosts.txt");
|
||||
if (addr != null)
|
||||
if (addr != null) {
|
||||
_addressbookLocation = addr;
|
||||
try {
|
||||
_petnames.load(addr);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String show = props.getProperty("showimages", "false");
|
||||
String show = props.getProperty("showimages", "true");
|
||||
_showImagesByDefault = (show != null) && (show.equals("true"));
|
||||
show = props.getProperty("showexpanded", "false");
|
||||
_showExpandedByDefault = (show != null) && (show.equals("true"));
|
||||
@ -182,7 +195,7 @@ public class User {
|
||||
try { return Integer.parseInt(val); } catch (NumberFormatException nfe) { return -1; }
|
||||
}
|
||||
|
||||
public static final String LOGIN_OK = "Logged in";
|
||||
public static final String LOGIN_OK = "<span class=\"b_loginMsgOk\">Logged in</span>";
|
||||
|
||||
public String export() {
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
|
@ -7,11 +7,14 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.Archive;
|
||||
import net.i2p.syndie.BlogManager;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Simple read-only summary of an archive
|
||||
*/
|
||||
public class ArchiveIndex {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
protected String _version;
|
||||
protected long _generatedOn;
|
||||
protected int _allBlogs;
|
||||
@ -31,9 +34,14 @@ public class ArchiveIndex {
|
||||
protected Properties _headers;
|
||||
|
||||
public ArchiveIndex() {
|
||||
this(false); //true);
|
||||
this(I2PAppContext.getGlobalContext(), false);
|
||||
}
|
||||
public ArchiveIndex(boolean shouldLoad) {
|
||||
public ArchiveIndex(I2PAppContext ctx) {
|
||||
this(ctx, false); //true);
|
||||
}
|
||||
public ArchiveIndex(I2PAppContext ctx, boolean shouldLoad) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(ArchiveIndex.class);
|
||||
_blogs = new ArrayList();
|
||||
_newestBlogs = new ArrayList();
|
||||
_newestEntries = new ArrayList();
|
||||
@ -117,6 +125,20 @@ public class ArchiveIndex {
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
public int getBlogEntryCount(Hash blog) {
|
||||
Set uris = new HashSet(64);
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
BlogSummary summary = (BlogSummary)_blogs.get(i);
|
||||
if (summary.blog.equals(blog)) {
|
||||
uris.addAll(summary.entries);
|
||||
//for (int j = 0; j < summary.entries.size(); j++) {
|
||||
// EntrySummary entry = (EntrySummary)summary.entries.get(j);
|
||||
// uris.add(entry.entry);
|
||||
//}
|
||||
}
|
||||
}
|
||||
return uris.size();
|
||||
}
|
||||
|
||||
/** how many 'new' blogs are listed */
|
||||
public int getNewestBlogCount() { return _newestBlogs.size(); }
|
||||
@ -264,7 +286,8 @@ public class ArchiveIndex {
|
||||
}
|
||||
if (tag != null) {
|
||||
if (!tag.equals(summary.tag)) {
|
||||
System.out.println("Tag [" + summary.tag + "] does not match the requested [" + tag + "] in " + summary.blog.toBase64());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Tag [" + summary.tag + "] does not match the requested [" + tag + "] in " + summary.blog.toBase64());
|
||||
if (false) {
|
||||
StringBuffer b = new StringBuffer(tag.length()*2);
|
||||
for (int j = 0; j < tag.length(); j++) {
|
||||
@ -276,7 +299,8 @@ public class ArchiveIndex {
|
||||
b.append('_');
|
||||
b.append(' ');
|
||||
}
|
||||
System.out.println("tag.summary: " + b.toString());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("tag.summary: " + b.toString());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -379,6 +403,14 @@ public class ArchiveIndex {
|
||||
size = kb;
|
||||
entry = uri;
|
||||
}
|
||||
public int hashCode() {
|
||||
return entry.hashCode();
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
if ( (obj instanceof EntrySummary) && (((EntrySummary)obj).entry.equals(entry)) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** export the index into an archive.txt */
|
||||
|
@ -4,6 +4,7 @@ import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Blog metadata. Formatted as: <pre>
|
||||
@ -57,12 +58,14 @@ public class BlogInfo {
|
||||
public static final String EDITION = "Edition";
|
||||
|
||||
public void load(InputStream in) throws IOException {
|
||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
|
||||
List names = new ArrayList();
|
||||
List vals = new ArrayList();
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
System.err.println("Read info line [" + line + "]");
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("Read info line [" + line + "]");
|
||||
line = line.trim();
|
||||
int len = line.length();
|
||||
int split = line.indexOf(':');
|
||||
@ -84,7 +87,7 @@ public class BlogInfo {
|
||||
for (int i = 0; i < _optionNames.length; i++) {
|
||||
_optionNames[i] = (String)names.get(i);
|
||||
_optionValues[i] = (String)vals.get(i);
|
||||
System.out.println("Loaded info: [" + _optionNames[i] + "] = [" + _optionValues[i] + "]");
|
||||
//System.out.println("Loaded info: [" + _optionNames[i] + "] = [" + _optionValues[i] + "]");
|
||||
}
|
||||
|
||||
String keyStr = getProperty(OWNER_KEY);
|
||||
@ -119,12 +122,12 @@ public class BlogInfo {
|
||||
for (int i = 0; i < _optionNames.length; i++) {
|
||||
if (_optionNames[i].equals(name)) {
|
||||
String val = _optionValues[i];
|
||||
System.out.println("getProperty[" + name + "] = [" + val + "] [sz=" + val.length() +"]");
|
||||
for (int j = 0; j < val.length(); j++) {
|
||||
char c = (char)val.charAt(j);
|
||||
if (c != (c & 0x7F))
|
||||
System.out.println("char " + j + ": " + (int)c);
|
||||
}
|
||||
//System.out.println("getProperty[" + name + "] = [" + val + "] [sz=" + val.length() +"]");
|
||||
//for (int j = 0; j < val.length(); j++) {
|
||||
// char c = (char)val.charAt(j);
|
||||
// if (c != (c & 0x7F))
|
||||
// System.out.println("char " + j + ": " + (int)c);
|
||||
//}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.util.zip.*;
|
||||
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Securely wrap up an entry and any attachments. Container format:<pre>
|
||||
@ -115,12 +116,19 @@ public class EntryContainer {
|
||||
if (len <= 0)
|
||||
break;
|
||||
int split = line.indexOf(':');
|
||||
if ( (split <= 0) || (split >= len - 2) )
|
||||
if (split <= 0) {
|
||||
throw new IOException("Invalid format of the syndie entry: line=" + line);
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1);
|
||||
_rawKeys.add(key);
|
||||
_rawValues.add(val);
|
||||
} else if (split >= len - 2) {
|
||||
// foo:\n
|
||||
String key = line.substring(0, split);
|
||||
_rawKeys.add(key);
|
||||
_rawValues.add("");
|
||||
} else {
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1);
|
||||
_rawKeys.add(key);
|
||||
_rawValues.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
parseHeaders();
|
||||
@ -159,7 +167,9 @@ public class EntryContainer {
|
||||
}
|
||||
|
||||
public void seal(I2PAppContext ctx, SigningPrivateKey signingKey, SessionKey entryKey) throws IOException {
|
||||
System.out.println("Sealing " + _entryURI);
|
||||
Log l = ctx.logManager().getLog(getClass());
|
||||
if (l.shouldLog(Log.DEBUG))
|
||||
l.debug("Sealing " + _entryURI);
|
||||
if (entryKey == null)
|
||||
_format = FORMAT_ZIP_UNENCRYPTED;
|
||||
else
|
||||
@ -265,17 +275,21 @@ public class EntryContainer {
|
||||
for (int i = 0; i < attachments.size(); i++) {
|
||||
byte data[] = (byte[])attachments.get(ZIP_ATTACHMENT_PREFIX + i + ZIP_ATTACHMENT_SUFFIX);
|
||||
byte metadata[] = (byte[])attachmentMeta.get(ZIP_ATTACHMENT_META_PREFIX + i + ZIP_ATTACHMENT_META_SUFFIX);
|
||||
if ( (data != null) && (metadata != null) )
|
||||
if ( (data != null) && (metadata != null) ) {
|
||||
_attachments[i] = new Attachment(data, metadata);
|
||||
else
|
||||
System.out.println("Unable to get " + i + ": " + data + "/" + metadata);
|
||||
} else {
|
||||
Log l = ctx.logManager().getLog(getClass());
|
||||
if (l.shouldLog(Log.WARN))
|
||||
l.warn("Unable to get " + i + ": " + data + "/" + metadata);
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("Attachments: " + _attachments.length + "/" + attachments.size() + ": " + attachments);
|
||||
}
|
||||
|
||||
public BlogURI getURI() { return _entryURI; }
|
||||
private static final String NO_TAGS[] = new String[0];
|
||||
public static final String NO_TAGS_TAG = "[none]";
|
||||
private static final String NO_TAGS[] = new String[] { NO_TAGS_TAG };
|
||||
public String[] getTags() {
|
||||
String tags = getHeader(HEADER_BLOGTAGS);
|
||||
if ( (tags == null) || (tags.trim().length() <= 0) ) {
|
||||
@ -340,8 +354,6 @@ public class EntryContainer {
|
||||
String idVal = getHeader(HEADER_ENTRYID);
|
||||
|
||||
if (keyHash == null) {
|
||||
System.err.println("Headers: " + _rawKeys);
|
||||
System.err.println("Values : " + _rawValues);
|
||||
throw new IOException("Missing " + HEADER_BLOGKEY + " header");
|
||||
}
|
||||
|
||||
@ -350,8 +362,6 @@ public class EntryContainer {
|
||||
try {
|
||||
entryId = Long.parseLong(idVal.trim());
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.err.println("Headers: " + _rawKeys);
|
||||
System.err.println("Values : " + _rawValues);
|
||||
throw new IOException("Invalid format of entryId (" + idVal + ")");
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,19 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.Archive;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* writable archive index (most are readonly)
|
||||
*/
|
||||
public class LocalArchiveIndex extends ArchiveIndex {
|
||||
|
||||
public LocalArchiveIndex() {
|
||||
super(false);
|
||||
private Log _log;
|
||||
public LocalArchiveIndex(I2PAppContext ctx) {
|
||||
super(ctx, false);
|
||||
_log = ctx.logManager().getLog(getClass());
|
||||
}
|
||||
|
||||
public void setGeneratedOn(long when) { _generatedOn = when; }
|
||||
@ -46,7 +49,8 @@ public class LocalArchiveIndex extends ArchiveIndex {
|
||||
if (summary.blog.equals(key) && (summary.tag.equals(tag)) ) {
|
||||
long entryId = Archive.getEntryIdFromIndexName(entry);
|
||||
int kb = Archive.getSizeFromIndexName(entry);
|
||||
System.out.println("Adding entry " + entryId + ", size=" + kb + "KB [" + entry + "]");
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Adding entry " + entryId + ", size=" + kb + "KB [" + entry + "]");
|
||||
EntrySummary entrySummary = new EntrySummary(new BlogURI(key, entryId), kb);
|
||||
for (int j = 0; j < summary.entries.size(); j++) {
|
||||
EntrySummary cur = (EntrySummary)summary.entries.get(j);
|
||||
|
@ -12,7 +12,7 @@ import net.i2p.syndie.BlogManager;
|
||||
* Simple read-only summary of an archive, proxied to the BlogManager's instance
|
||||
*/
|
||||
public class TransparentArchiveIndex extends ArchiveIndex {
|
||||
public TransparentArchiveIndex() { super(false); }
|
||||
public TransparentArchiveIndex() { super(I2PAppContext.getGlobalContext(), false); }
|
||||
|
||||
private static ArchiveIndex index() { return BlogManager.instance().getArchive().getIndex(); }
|
||||
|
||||
|
@ -1,52 +1,108 @@
|
||||
package net.i2p.syndie.sml;
|
||||
|
||||
import java.util.List;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class EventReceiverImpl implements SMLParser.EventReceiver {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
|
||||
public EventReceiverImpl(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(EventReceiverImpl.class);
|
||||
}
|
||||
public void receiveHeader(String header, String value) {
|
||||
System.out.println("Receive header [" + header + "] = [" + value + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive header [" + header + "] = [" + value + "]");
|
||||
}
|
||||
public void receiveLink(String schema, String location, String text) {
|
||||
System.out.println("Receive link [" + schema + "]/[" + location+ "]/[" + text + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive link [" + schema + "]/[" + location+ "]/[" + text + "]");
|
||||
}
|
||||
public void receiveBlog(String name, String blogKeyHash, String blogPath, long blogEntryId,
|
||||
List blogArchiveLocations, String anchorText) {
|
||||
System.out.println("Receive blog [" + name + "]/[" + blogKeyHash + "]/[" + blogPath
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive blog [" + name + "]/[" + blogKeyHash + "]/[" + blogPath
|
||||
+ "]/[" + blogEntryId + "]/[" + blogArchiveLocations + "]/[" + anchorText + "]");
|
||||
}
|
||||
public void receiveArchive(String name, String description, String locationSchema, String location,
|
||||
String postingKey, String anchorText) {
|
||||
System.out.println("Receive archive [" + name + "]/[" + description + "]/[" + locationSchema
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive archive [" + name + "]/[" + description + "]/[" + locationSchema
|
||||
+ "]/[" + location + "]/[" + postingKey + "]/[" + anchorText + "]");
|
||||
}
|
||||
public void receiveImage(String alternateText, int attachmentId) {
|
||||
System.out.println("Receive image [" + alternateText + "]/[" + attachmentId + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive image [" + alternateText + "]/[" + attachmentId + "]");
|
||||
}
|
||||
public void receiveAddress(String name, String schema, String location, String anchorText) {
|
||||
System.out.println("Receive address [" + name + "]/[" + schema + "]/[" + location + "]/[" + anchorText+ "]");
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive address [" + name + "]/[" + schema + "]/[" + location + "]/[" + anchorText+ "]");
|
||||
}
|
||||
public void receiveBold(String text) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive bold [" + text+ "]");
|
||||
}
|
||||
public void receiveItalic(String text) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive italic [" + text+ "]");
|
||||
}
|
||||
public void receiveUnderline(String text) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive underline [" + text+ "]");
|
||||
}
|
||||
public void receiveBold(String text) { System.out.println("Receive bold [" + text+ "]"); }
|
||||
public void receiveItalic(String text) { System.out.println("Receive italic [" + text+ "]"); }
|
||||
public void receiveUnderline(String text) { System.out.println("Receive underline [" + text+ "]"); }
|
||||
public void receiveQuote(String text, String whoQuoted, String quoteLocationSchema, String quoteLocation) {
|
||||
System.out.println("Receive quote [" + text + "]/[" + whoQuoted + "]/[" + quoteLocationSchema + "]/[" + quoteLocation + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive quote [" + text + "]/[" + whoQuoted + "]/[" + quoteLocationSchema + "]/[" + quoteLocation + "]");
|
||||
}
|
||||
public void receiveCode(String text, String codeLocationSchema, String codeLocation) {
|
||||
System.out.println("Receive code [" + text+ "]/[" + codeLocationSchema + "]/[" + codeLocation + "]");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive code [" + text+ "]/[" + codeLocationSchema + "]/[" + codeLocation + "]");
|
||||
}
|
||||
public void receiveCut(String summaryText) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive cut [" + summaryText + "]");
|
||||
}
|
||||
public void receivePlain(String text) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive plain [" + text + "]");
|
||||
}
|
||||
public void receiveNewline() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive NL");
|
||||
}
|
||||
public void receiveLT() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive LT");
|
||||
}
|
||||
public void receiveGT() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive GT");
|
||||
}
|
||||
public void receiveBegin() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive begin");
|
||||
}
|
||||
public void receiveEnd() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive end");
|
||||
}
|
||||
public void receiveHeaderEnd() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive header end");
|
||||
}
|
||||
public void receiveLeftBracket() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive [");
|
||||
}
|
||||
public void receiveRightBracket() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receive ]");
|
||||
}
|
||||
public void receiveCut(String summaryText) { System.out.println("Receive cut [" + summaryText + "]"); }
|
||||
public void receivePlain(String text) { System.out.println("Receive plain [" + text + "]"); }
|
||||
public void receiveNewline() { System.out.println("Receive NL"); }
|
||||
public void receiveLT() { System.out.println("Receive LT"); }
|
||||
public void receiveGT() { System.out.println("Receive GT"); }
|
||||
public void receiveBegin() { System.out.println("Receive begin"); }
|
||||
public void receiveEnd() { System.out.println("Receive end"); }
|
||||
public void receiveHeaderEnd() { System.out.println("Receive header end"); }
|
||||
public void receiveLeftBracket() { System.out.println("Receive ["); }
|
||||
public void receiveRightBracket() { System.out.println("Receive ]"); }
|
||||
|
||||
public void receiveH1(String text) {}
|
||||
public void receiveH2(String text) {}
|
||||
|
@ -3,6 +3,7 @@ package net.i2p.syndie.sml;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
@ -16,8 +17,8 @@ public class HTMLPreviewRenderer extends HTMLRenderer {
|
||||
private List _fileTypes;
|
||||
private List _files;
|
||||
|
||||
public HTMLPreviewRenderer(List filenames, List fileTypes, List files) {
|
||||
super();
|
||||
public HTMLPreviewRenderer(I2PAppContext ctx, List filenames, List fileTypes, List files) {
|
||||
super(ctx);
|
||||
_filenames = filenames;
|
||||
_fileTypes = fileTypes;
|
||||
_files = files;
|
||||
@ -37,23 +38,24 @@ public class HTMLPreviewRenderer extends HTMLRenderer {
|
||||
File f = (File)_files.get(id);
|
||||
String name = (String)_filenames.get(id);
|
||||
String type = (String)_fileTypes.get(id);
|
||||
_bodyBuffer.append("<a href=\"").append(getAttachmentURL(id)).append("\">");
|
||||
_bodyBuffer.append("<a ").append(getClass("attachmentView")).append(" href=\"").append(getAttachmentURL(id)).append("\">");
|
||||
_bodyBuffer.append(sanitizeString(anchorText)).append("</a>");
|
||||
_bodyBuffer.append(" (").append(f.length()/1024).append("KB, ");
|
||||
_bodyBuffer.append(" \"").append(sanitizeString(name)).append("\", ");
|
||||
_bodyBuffer.append(sanitizeString(type)).append(")");
|
||||
_bodyBuffer.append(getSpan("attachmentSummary")).append(" (");
|
||||
_bodyBuffer.append(getSpan("attachmentSummarySize")).append(f.length()/1024).append("KB</span>, ");
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryName")).append(" \"").append(sanitizeString(name)).append("\"</span>, ");
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryType")).append(sanitizeString(type)).append("</span>)</span>");
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveEnd() {
|
||||
_postBodyBuffer.append("</td></tr>\n");
|
||||
_postBodyBuffer.append("<tr>\n");
|
||||
_postBodyBuffer.append("<tr ").append(getClass("summDetail")).append(" >\n");
|
||||
_postBodyBuffer.append("<form action=\"").append(getAttachmentURLBase()).append("\">\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" class=\"syndieEntryAttachmentsCell\"\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" ").append(getClass("summDetail")).append("> \n");
|
||||
|
||||
if (_files.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Attachments:</b> ");
|
||||
_postBodyBuffer.append("<select name=\"").append(ArchiveViewerBean.PARAM_ATTACHMENT).append("\">\n");
|
||||
_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 < _files.size(); i++) {
|
||||
_postBodyBuffer.append("<option value=\"").append(i).append("\">");
|
||||
File f = (File)_files.get(i);
|
||||
@ -64,53 +66,77 @@ public class HTMLPreviewRenderer extends HTMLRenderer {
|
||||
_postBodyBuffer.append(", type ").append(sanitizeString(type)).append(")</option>\n");
|
||||
}
|
||||
_postBodyBuffer.append("</select>\n");
|
||||
_postBodyBuffer.append("<input type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
_postBodyBuffer.append("<input ").append(getClass("summDetailAttachmentDl")).append(" type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
}
|
||||
|
||||
if (_blogs.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Blog references:</b> ");
|
||||
_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 href=\"").append(getPageURL(new Hash(Base64.decode(b.hash)), b.tag, b.entryId, -1, -1, (_user != null ? _user.getShowExpanded() : false), (_user != null ? _user.getShowImages() : false)));
|
||||
boolean expanded = (_user != null ? _user.getShowExpanded() : false);
|
||||
boolean images = (_user != null ? _user.getShowImages() : false);
|
||||
_postBodyBuffer.append("<a ").append(getClass("summDetailBlogLink")).append(" href=\"");
|
||||
_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("<b>External links:</b> ");
|
||||
_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 href=\"externallink.jsp?schema=");
|
||||
_postBodyBuffer.append(sanitizeURL(l.schema)).append("&location=");
|
||||
_postBodyBuffer.append(sanitizeURL(l.location));
|
||||
_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));
|
||||
_postBodyBuffer.append(" (").append(sanitizeString(l.schema)).append(")</a> ");
|
||||
_postBodyBuffer.append(getSpan("summDetailExternalNet")).append(" (").append(sanitizeString(l.schema)).append(")</span></a> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_addresses.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Addresses:</b> ");
|
||||
_postBodyBuffer.append(getSpan("summDetailAddr")).append("Addresses:</span>");
|
||||
for (int i = 0; i < _addresses.size(); i++) {
|
||||
Address a = (Address)_addresses.get(i);
|
||||
_postBodyBuffer.append("<a href=\"addaddress.jsp?schema=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.schema)).append("&location=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.location)).append("&name=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.name));
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name));
|
||||
|
||||
String knownName = null;
|
||||
if (_user != null)
|
||||
knownName = _user.getPetNameDB().getNameByLocation(a.location);
|
||||
if (knownName != null) {
|
||||
_postBodyBuffer.append(' ').append(getSpan("summDetailAddrKnown"));
|
||||
_postBodyBuffer.append(sanitizeString(knownName)).append("</span>");
|
||||
} else {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailAddrLink")).append(" href=\"addresses.jsp?");
|
||||
if (a.schema != null)
|
||||
_postBodyBuffer.append("network=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
if (a.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeTagParam(a.location)).append('&');
|
||||
if (a.name != null)
|
||||
_postBodyBuffer.append("name=").append(sanitizeTagParam(a.name)).append('&');
|
||||
if (a.protocol != null)
|
||||
_postBodyBuffer.append("protocol=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_archives.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Archives:</b>");
|
||||
_postBodyBuffer.append(getSpan("summDetailArchive")).append("Archives:</span>");
|
||||
for (int i = 0; i < _archives.size(); i++) {
|
||||
ArchiveRef a = (ArchiveRef)_archives.get(i);
|
||||
_postBodyBuffer.append(" <a href=\"").append(getArchiveURL(null, new SafeURL(a.locationSchema + "://" + a.location)));
|
||||
_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(sanitizeString(a.description));
|
||||
_postBodyBuffer.append(": ").append(getSpan("summDetailArchiveDesc")).append(sanitizeString(a.description)).append("</span>");
|
||||
if (null == _user.getPetNameDB().getNameByLocation(a.location)) {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveBookmark")).append(" href=\"");
|
||||
_postBodyBuffer.append(getBookmarkURL(a.name, a.location, a.locationSchema, "syndiearchive"));
|
||||
_postBodyBuffer.append("\">bookmark</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
@ -3,15 +3,19 @@ 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 HTMLRenderer extends EventReceiverImpl {
|
||||
private Log _log;
|
||||
protected SMLParser _parser;
|
||||
protected Writer _out;
|
||||
protected User _user;
|
||||
@ -31,8 +35,10 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
protected StringBuffer _bodyBuffer;
|
||||
protected StringBuffer _postBodyBuffer;
|
||||
|
||||
public HTMLRenderer() {
|
||||
_parser = new SMLParser();
|
||||
public HTMLRenderer(I2PAppContext ctx) {
|
||||
super(ctx);
|
||||
_log = ctx.logManager().getLog(HTMLRenderer.class);
|
||||
_parser = new SMLParser(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +49,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
System.err.println("Usage: HTMLRenderer smlFile outputFile");
|
||||
return;
|
||||
}
|
||||
HTMLRenderer renderer = new HTMLRenderer();
|
||||
HTMLRenderer renderer = new HTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
Writer out = null;
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024*512);
|
||||
@ -61,20 +67,49 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve: class="s_summary_$element" or class="s_detail_$element ss_$style_detail_$element"
|
||||
*/
|
||||
protected String getClass(String element) {
|
||||
StringBuffer rv = new StringBuffer(64);
|
||||
rv.append(" class=\"s_");
|
||||
if (_cutBody)
|
||||
rv.append("summary_");
|
||||
else
|
||||
rv.append("detail_");
|
||||
rv.append(element);
|
||||
if (_entry != null) {
|
||||
String style = sanitizeStyle(_entry.getHeader(HEADER_STYLE));
|
||||
if (style != null) {
|
||||
rv.append(" ss_").append(style);
|
||||
if (_cutBody)
|
||||
rv.append("summary_");
|
||||
else
|
||||
rv.append("detail_");
|
||||
rv.append(element);
|
||||
}
|
||||
}
|
||||
rv.append("\" ");
|
||||
return rv.toString();
|
||||
}
|
||||
protected String getSpan(String element) {
|
||||
return "<span " + getClass(element) + ">";
|
||||
}
|
||||
|
||||
public void renderUnknownEntry(User user, Archive archive, BlogURI uri, Writer out) throws IOException {
|
||||
BlogInfo info = archive.getBlogInfo(uri);
|
||||
if (info == null)
|
||||
out.write("<br />The blog " + uri.getKeyHash().toBase64() + " is not known locally. "
|
||||
+ "Please get it from an archive and <a href=\""
|
||||
out.write("<br /><span " + getClass("unknownBlog") + ">The blog <span " + getClass("blogURI") + ">" + uri.getKeyHash().toBase64() + "</span> is not known locally. "
|
||||
+ "Please get it from an archive and <a " + getClass("unknownRetry") + " href=\""
|
||||
+ getPageURL(uri.getKeyHash(), null, uri.getEntryId(), -1, -1, user.getShowExpanded(), user.getShowImages())
|
||||
+ "\">try again</a>");
|
||||
+ "\">try again</a></span>");
|
||||
else
|
||||
out.write("<br />The blog <a href=\""
|
||||
out.write("<br /><span " + getClass("unknownEntry") + ">The blog <a " + getClass("unknownRetry") + " href=\""
|
||||
+ getPageURL(uri.getKeyHash(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())
|
||||
+ "\">" + info.getProperty(BlogInfo.NAME) + "</a> is known, but the entry " + uri.getEntryId() + " is not. "
|
||||
+ "Please get it from an archive and <a href=\""
|
||||
+ "Please get it from an archive and <a " + getClass("unknownRetry") + " href=\""
|
||||
+ getPageURL(uri.getKeyHash(), null, uri.getEntryId(), -1, -1, user.getShowExpanded(), user.getShowImages())
|
||||
+ "\">try again</a>");
|
||||
+ "\">try again</a></span>");
|
||||
}
|
||||
|
||||
public void render(User user, Archive archive, EntryContainer entry, Writer out, boolean cutBody, boolean showImages) throws IOException {
|
||||
@ -83,6 +118,15 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
render(user, archive, entry, entry.getEntry().getText(), out, cutBody, showImages);
|
||||
}
|
||||
public void render(User user, Archive archive, EntryContainer entry, String rawSML, Writer out, boolean cutBody, boolean showImages) throws IOException {
|
||||
prepare(user, archive, entry, rawSML, out, cutBody, showImages);
|
||||
|
||||
_out.write(_preBodyBuffer.toString());
|
||||
_out.write(_bodyBuffer.toString());
|
||||
_out.write(_postBodyBuffer.toString());
|
||||
//int len = _preBodyBuffer.length() + _bodyBuffer.length() + _postBodyBuffer.length();
|
||||
//System.out.println("Wrote " + len);
|
||||
}
|
||||
protected void prepare(User user, Archive archive, EntryContainer entry, String rawSML, Writer out, boolean cutBody, boolean showImages) throws IOException {
|
||||
_user = user;
|
||||
_archive = archive;
|
||||
_entry = entry;
|
||||
@ -100,11 +144,6 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_cutReached = false;
|
||||
_cutSize = 1024;
|
||||
_parser.parse(rawSML, this);
|
||||
_out.write(_preBodyBuffer.toString());
|
||||
_out.write(_bodyBuffer.toString());
|
||||
_out.write(_postBodyBuffer.toString());
|
||||
//int len = _preBodyBuffer.length() + _bodyBuffer.length() + _postBodyBuffer.length();
|
||||
//System.out.println("Wrote " + len);
|
||||
}
|
||||
|
||||
public void receivePlain(String text) {
|
||||
@ -114,64 +153,64 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
public void receiveBold(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<b>").append(sanitizeString(text)).append("</b>");
|
||||
_bodyBuffer.append("<em ").append(getClass("bold")).append(" >").append(sanitizeString(text)).append("</em>");
|
||||
}
|
||||
public void receiveItalic(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<i>").append(sanitizeString(text)).append("</i>");
|
||||
_bodyBuffer.append("<em ").append(getClass("italic")).append(" >").append(sanitizeString(text)).append("</em>");
|
||||
}
|
||||
public void receiveUnderline(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<u>").append(sanitizeString(text)).append("</u>");
|
||||
_bodyBuffer.append("<em ").append(getClass("underline")).append(" >").append(sanitizeString(text)).append("</em>");
|
||||
}
|
||||
public void receiveHR() {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<hr />");
|
||||
_bodyBuffer.append(getSpan("hr")).append("<hr /></span>");
|
||||
}
|
||||
public void receiveH1(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<h1>").append(sanitizeString(body)).append("</h1>");
|
||||
_bodyBuffer.append("<h1 ").append(getClass("h1")).append(" >").append(sanitizeString(body)).append("</span></h1>");
|
||||
}
|
||||
public void receiveH2(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<h2>").append(sanitizeString(body)).append("</h2>");
|
||||
_bodyBuffer.append("<h2 ").append(getClass("h2")).append(" >").append(sanitizeString(body)).append("</span></h2>");
|
||||
}
|
||||
public void receiveH3(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<h3>").append(sanitizeString(body)).append("</h3>");
|
||||
_bodyBuffer.append("<h3 ").append(getClass("h3")).append(" >").append(sanitizeString(body)).append("</span></h3>");
|
||||
}
|
||||
public void receiveH4(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<h4>").append(sanitizeString(body)).append("</h4>");
|
||||
_bodyBuffer.append("<h4 ").append(getClass("h4")).append(" >").append(sanitizeString(body)).append("</span></h4>");
|
||||
}
|
||||
public void receiveH5(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<h5>").append(sanitizeString(body)).append("</h5>");
|
||||
_bodyBuffer.append("<h5 ").append(getClass("h5")).append(" >").append(sanitizeString(body)).append("</span></h5>");
|
||||
}
|
||||
public void receivePre(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<pre>").append(sanitizeString(body)).append("</pre>");
|
||||
_bodyBuffer.append("<pre ").append(getClass("pre")).append(" >").append(sanitizeString(body)).append("</pre>");
|
||||
}
|
||||
|
||||
public void receiveQuote(String text, String whoQuoted, String quoteLocationSchema, String quoteLocation) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<quote>").append(sanitizeString(text)).append("</quote>");
|
||||
_bodyBuffer.append("<quote ").append(getClass("quote")).append(" >").append(sanitizeString(text)).append("</quote>");
|
||||
}
|
||||
public void receiveCode(String text, String codeLocationSchema, String codeLocation) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<code>").append(sanitizeString(text)).append("</code>");
|
||||
_bodyBuffer.append("<code ").append(getClass("code")).append(" >").append(sanitizeString(text)).append("</code>");
|
||||
}
|
||||
public void receiveImage(String alternateText, int attachmentId) {
|
||||
if (!continueBody()) { return; }
|
||||
if (_showImages) {
|
||||
_bodyBuffer.append("<img src=\"").append(getAttachmentURL(attachmentId)).append("\"");
|
||||
_bodyBuffer.append("<img ").append(getClass("img")).append(" src=\"").append(getAttachmentURL(attachmentId)).append("\"");
|
||||
if (alternateText != null)
|
||||
_bodyBuffer.append(" alt=\"").append(sanitizeTagParam(alternateText)).append("\"");
|
||||
_bodyBuffer.append(" />");
|
||||
} else {
|
||||
_bodyBuffer.append("[image: attachment ").append(attachmentId);
|
||||
_bodyBuffer.append(": ").append(sanitizeString(alternateText));
|
||||
_bodyBuffer.append(" <a href=\"").append(getEntryURL(true)).append("\">view images</a>]");
|
||||
_bodyBuffer.append(getSpan("imgSummary")).append("[image: ").append(getSpan("imgSummaryAttachment")).append(" attachment ").append(attachmentId);
|
||||
_bodyBuffer.append(":</span> ").append(getSpan("imgSummaryAlt")).append(sanitizeString(alternateText));
|
||||
_bodyBuffer.append("</span> <a ").append(getClass("imgSummaryLink")).append(" href=\"").append(getEntryURL(true)).append("\">view images</a>]</span>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +218,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
if (!continueBody()) { return; }
|
||||
_cutReached = true;
|
||||
if (_cutBody) {
|
||||
_bodyBuffer.append("<a href=\"").append(getEntryURL()).append("\">");
|
||||
_bodyBuffer.append("<a ").append(getClass("cutExplicit")).append(" href=\"").append(getEntryURL()).append("\">");
|
||||
if ( (summaryText != null) && (summaryText.length() > 0) )
|
||||
_bodyBuffer.append(sanitizeString(summaryText));
|
||||
else
|
||||
@ -187,7 +226,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_bodyBuffer.append("</a>\n");
|
||||
} else {
|
||||
if (summaryText != null)
|
||||
_bodyBuffer.append(sanitizeString(summaryText));
|
||||
_bodyBuffer.append(getSpan("cutIgnore")).append(sanitizeString(summaryText)).append("</span>\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,7 +237,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
// System.out.println("rv: " + rv + " Cut reached: " + _cutReached + " bodyBufferSize: " + _bodyBuffer.length() + " cutBody? " + _cutBody);
|
||||
if (!rv && !_cutReached) {
|
||||
// exceeded the allowed size
|
||||
_bodyBuffer.append("<a href=\"").append(getEntryURL()).append("\">more inside...</a>");
|
||||
_bodyBuffer.append("<a ").append(getClass("cutImplicit")).append(" href=\"").append(getEntryURL()).append("\">more inside...</a>\n");
|
||||
_cutReached = true;
|
||||
}
|
||||
return rv;
|
||||
@ -207,26 +246,26 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
public void receiveNewline() {
|
||||
if (!continueBody()) { return; }
|
||||
if (true || (_lastNewlineAt >= _bodyBuffer.length()))
|
||||
_bodyBuffer.append("<br />\n");
|
||||
_bodyBuffer.append(getSpan("nl")).append("<br /></span>\n");
|
||||
else
|
||||
_lastNewlineAt = _bodyBuffer.length();
|
||||
}
|
||||
public void receiveLT() {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append("<");
|
||||
_bodyBuffer.append(getSpan("lt")).append("<</span>");
|
||||
}
|
||||
public void receiveGT() {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(">");
|
||||
_bodyBuffer.append(getSpan("gt")).append("></span>");
|
||||
}
|
||||
public void receiveBegin() {}
|
||||
public void receiveLeftBracket() {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append('[');
|
||||
_bodyBuffer.append(getSpan("lb")).append("[</span>");
|
||||
}
|
||||
public void receiveRightBracket() {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(']');
|
||||
_bodyBuffer.append(getSpan("rb")).append("]</span>");
|
||||
}
|
||||
|
||||
protected static class Blog {
|
||||
@ -263,7 +302,8 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
*
|
||||
*/
|
||||
public void receiveBlog(String name, String hash, String tag, long entryId, List locations, String description) {
|
||||
System.out.println("Receiving the blog: " + name + "/" + hash + "/" + tag + "/" + entryId +"/" + locations + ": "+ description);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Receiving the blog: " + name + "/" + hash + "/" + tag + "/" + entryId +"/" + locations + ": "+ description);
|
||||
byte blogData[] = Base64.decode(hash);
|
||||
if ( (blogData == null) || (blogData.length != Hash.HASH_LENGTH) )
|
||||
return;
|
||||
@ -283,7 +323,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
Hash blog = new Hash(blogData);
|
||||
if (entryId > 0) {
|
||||
String pageURL = getPageURL(blog, tag, entryId, -1, -1, true, (_user != null ? _user.getShowImages() : false));
|
||||
_bodyBuffer.append("<a href=\"").append(pageURL).append("\">");
|
||||
_bodyBuffer.append("<a ").append(getClass("blogEntryLink")).append(" href=\"").append(pageURL).append("\">");
|
||||
if ( (description != null) && (description.trim().length() > 0) ) {
|
||||
_bodyBuffer.append(sanitizeString(description));
|
||||
} else if ( (name != null) && (name.trim().length() > 0) ) {
|
||||
@ -296,29 +336,30 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
|
||||
String url = getPageURL(blog, null, -1, -1, -1, (_user != null ? _user.getShowExpanded() : false), (_user != null ? _user.getShowImages() : false));
|
||||
_bodyBuffer.append(" [<a href=\"").append(url);
|
||||
_bodyBuffer.append(getSpan("blogEntrySummary")).append(" [<a ").append(getClass("blogLink")).append(" href=\"").append(url);
|
||||
_bodyBuffer.append("\">");
|
||||
if ( (name != null) && (name.trim().length() > 0) )
|
||||
_bodyBuffer.append(sanitizeString(name));
|
||||
else
|
||||
_bodyBuffer.append("view");
|
||||
_bodyBuffer.append("</a> (<a href=\"").append(getMetadataURL(blog)).append("\">meta</a>)");
|
||||
_bodyBuffer.append("</a> (<a ").append(getClass("blogMeta")).append(" href=\"").append(getMetadataURL(blog)).append("\">meta</a>)");
|
||||
if ( (tag != null) && (tag.trim().length() > 0) ) {
|
||||
url = getPageURL(blog, tag, -1, -1, -1, false, false);
|
||||
_bodyBuffer.append(" <a href=\"").append(url);
|
||||
_bodyBuffer.append(" <a ").append(getClass("blogTagLink")).append(" href=\"").append(url);
|
||||
_bodyBuffer.append("\">Tag: ").append(sanitizeString(tag)).append("</a>");
|
||||
}
|
||||
if ( (locations != null) && (locations.size() > 0) ) {
|
||||
_bodyBuffer.append(" Archives: ");
|
||||
_bodyBuffer.append(getSpan("blogArchive")).append(" Archives: ");
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
SafeURL surl = (SafeURL)locations.get(i);
|
||||
if (_user.getAuthenticated() && _user.getAllowAccessRemote())
|
||||
_bodyBuffer.append("<a href=\"").append(getArchiveURL(blog, surl)).append("\">").append(sanitizeString(surl.toString())).append("</a> ");
|
||||
if (_user.getAuthenticated() && BlogManager.instance().authorizeRemote(_user) )
|
||||
_bodyBuffer.append("<a ").append(getClass("blogArchiveView")).append(" href=\"").append(getArchiveURL(blog, surl)).append("\">").append(sanitizeString(surl.toString())).append("</a> ");
|
||||
else
|
||||
_bodyBuffer.append(sanitizeString(surl.toString())).append(' ');
|
||||
_bodyBuffer.append(getSpan("blogArchiveURL")).append(sanitizeString(surl.toString())).append("</span> ");
|
||||
}
|
||||
_bodyBuffer.append("</span>");
|
||||
}
|
||||
_bodyBuffer.append("] ");
|
||||
_bodyBuffer.append("]</span> ");
|
||||
}
|
||||
|
||||
protected static class ArchiveRef {
|
||||
@ -346,18 +387,24 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
if (!continueBody()) { return; }
|
||||
|
||||
_bodyBuffer.append(sanitizeString(anchorText)).append(" [Archive ");
|
||||
_bodyBuffer.append(getSpan("archive")).append(sanitizeString(anchorText)).append("</span>");
|
||||
_bodyBuffer.append(getSpan("archiveSummary")).append(" [Archive ");
|
||||
if (name != null)
|
||||
_bodyBuffer.append(sanitizeString(name));
|
||||
_bodyBuffer.append(getSpan("archiveSummaryName")).append(sanitizeString(name)).append("</span>");
|
||||
if (location != null) {
|
||||
_bodyBuffer.append(" at ");
|
||||
SafeURL surl = new SafeURL(locationSchema + "://" + location);
|
||||
_bodyBuffer.append("<a href=\"").append(getArchiveURL(null, surl));
|
||||
_bodyBuffer.append("<a ").append(getClass("archiveSummaryLink")).append(" href=\"").append(getArchiveURL(null, surl));
|
||||
_bodyBuffer.append("\">").append(sanitizeString(surl.toString())).append("</a>");
|
||||
if (_user.getAuthenticated()) {
|
||||
_bodyBuffer.append(" <a ").append(getClass("archiveBookmarkLink")).append(" href=\"");
|
||||
_bodyBuffer.append(getBookmarkURL(sanitizeString(name), surl.getLocation(), surl.getSchema(), "syndiearchive"));
|
||||
_bodyBuffer.append("\">bookmark it</a>");
|
||||
}
|
||||
}
|
||||
if (description != null)
|
||||
_bodyBuffer.append(": ").append(sanitizeString(description));
|
||||
_bodyBuffer.append("]");
|
||||
_bodyBuffer.append(": ").append(getSpan("archiveSummaryDesc")).append(sanitizeString(description)).append("</span>");
|
||||
_bodyBuffer.append("]</span>");
|
||||
}
|
||||
|
||||
protected static class Link {
|
||||
@ -377,7 +424,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_links.add(l);
|
||||
if (!continueBody()) { return; }
|
||||
if ( (schema == null) || (location == null) ) return;
|
||||
_bodyBuffer.append("<a href=\"externallink.jsp?schema=");
|
||||
_bodyBuffer.append("<a ").append(getClass("externalLink")).append(" href=\"externallink.jsp?schema=");
|
||||
_bodyBuffer.append(sanitizeURL(schema)).append("&location=");
|
||||
_bodyBuffer.append(sanitizeURL(location)).append("&description=");
|
||||
_bodyBuffer.append(sanitizeURL(text)).append("\">").append(sanitizeString(text)).append("</a>");
|
||||
@ -387,48 +434,69 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
public String name;
|
||||
public String schema;
|
||||
public String location;
|
||||
public String protocol;
|
||||
public int hashCode() { return -1; }
|
||||
public boolean equals(Object o) {
|
||||
Address a = (Address)o;
|
||||
return DataHelper.eq(schema, a.schema) && DataHelper.eq(location, a.location) && DataHelper.eq(name, a.name);
|
||||
return DataHelper.eq(schema, a.schema) && DataHelper.eq(location, a.location) && DataHelper.eq(protocol, a.protocol) && DataHelper.eq(name, a.name);
|
||||
}
|
||||
}
|
||||
public void receiveAddress(String name, String schema, String location, String anchorText) {
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText) {
|
||||
Address a = new Address();
|
||||
a.name = name;
|
||||
a.schema = schema;
|
||||
a.location = location;
|
||||
a.protocol = protocol;
|
||||
if (!_addresses.contains(a))
|
||||
_addresses.add(a);
|
||||
if (!continueBody()) { return; }
|
||||
if ( (schema == null) || (location == null) ) return;
|
||||
_bodyBuffer.append("<a href=\"addaddress.jsp?schema=");
|
||||
_bodyBuffer.append(sanitizeURL(schema)).append("&name=");
|
||||
_bodyBuffer.append(sanitizeURL(name)).append("&location=");
|
||||
_bodyBuffer.append(sanitizeURL(location)).append("\">").append(sanitizeString(anchorText)).append("</a>");
|
||||
String knownName = null;
|
||||
if (_user != null)
|
||||
knownName = _user.getPetNameDB().getNameByLocation(location);
|
||||
if (knownName != null) {
|
||||
_bodyBuffer.append(getSpan("addr")).append(sanitizeString(anchorText)).append("</span>");
|
||||
_bodyBuffer.append(getSpan("addrKnownName")).append("(").append(sanitizeString(knownName)).append(")</span>");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_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('&');
|
||||
if (name != null)
|
||||
_bodyBuffer.append("name=").append(sanitizeTagParam(name)).append('&');
|
||||
if (protocol != null)
|
||||
_bodyBuffer.append("protocol=").append(sanitizeTagParam(protocol)).append('&');
|
||||
if (location != null)
|
||||
_bodyBuffer.append("location=").append(sanitizeTagParam(location));
|
||||
_bodyBuffer.append("\">").append(sanitizeString(anchorText)).append("</a>");
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveAttachment(int id, String anchorText) {
|
||||
if (!continueBody()) { return; }
|
||||
Attachment attachments[] = _entry.getAttachments();
|
||||
if ( (id < 0) || (id >= attachments.length)) {
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
_bodyBuffer.append(getSpan("attachmentUnknown")).append(sanitizeString(anchorText)).append("</span>");
|
||||
} else {
|
||||
_bodyBuffer.append("<a href=\"").append(getAttachmentURL(id)).append("\">");
|
||||
_bodyBuffer.append("<a ").append(getClass("attachmentView")).append(" href=\"").append(getAttachmentURL(id)).append("\">");
|
||||
_bodyBuffer.append(sanitizeString(anchorText)).append("</a>");
|
||||
_bodyBuffer.append(" (").append(attachments[id].getDataLength()/1024).append("KB, ");
|
||||
_bodyBuffer.append(" \"").append(sanitizeString(attachments[id].getName())).append("\", ");
|
||||
_bodyBuffer.append(sanitizeString(attachments[id].getMimeType())).append(")");
|
||||
_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>, ");
|
||||
_bodyBuffer.append(getSpan("attachmentSummaryType")).append(sanitizeString(attachments[id].getMimeType())).append("</span>)</span>");
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveEnd() {
|
||||
_postBodyBuffer.append("</td></tr>\n");
|
||||
_postBodyBuffer.append("</td></tr>\n<!-- end of the post body -->");
|
||||
if (_cutBody) {
|
||||
_postBodyBuffer.append("<tr class=\"syndieEntryAttachmentsCell\">\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" class=\"syndieEntryAttachmentsCell\">");
|
||||
_postBodyBuffer.append("<a href=\"").append(getEntryURL()).append("\">View details...</a> ");
|
||||
|
||||
_postBodyBuffer.append("<!-- beginning of the post summary -->\n");
|
||||
_postBodyBuffer.append("<tr ").append(getClass("summ")).append(">\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" ").append(getClass("summ")).append(" >");
|
||||
_postBodyBuffer.append("<a ").append(getClass("summLink")).append(" href=\"").append(getEntryURL()).append("\">View details...</a> ");
|
||||
_postBodyBuffer.append(getSpan("summ"));
|
||||
if ( (_entry != null) && (_entry.getAttachments() != null) && (_entry.getAttachments().length > 0) ) {
|
||||
int num = _entry.getAttachments().length;
|
||||
if (num == 1)
|
||||
@ -447,7 +515,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
if (links == 1)
|
||||
_postBodyBuffer.append("1 external link ");
|
||||
else if (links > 1)
|
||||
_postBodyBuffer.append(links).append(" external links");
|
||||
_postBodyBuffer.append(links).append(" external links ");
|
||||
|
||||
int addrs = _addresses.size();
|
||||
if (addrs == 1)
|
||||
@ -473,11 +541,13 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) )
|
||||
_postBodyBuffer.append(" <a href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a>\n");
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summParent")).append(" href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a>\n");
|
||||
|
||||
_postBodyBuffer.append("</td></tr>\n");
|
||||
_postBodyBuffer.append("</span></td></tr>\n");
|
||||
_postBodyBuffer.append("<!-- end of the post summary -->\n");
|
||||
} else {
|
||||
_postBodyBuffer.append("<tr class=\"syndieEntryAttachmentsCell\">\n");
|
||||
_postBodyBuffer.append("<!-- beginning of the post summary details -->\n");
|
||||
_postBodyBuffer.append("<tr ").append(getClass("summDetail")).append(">\n");
|
||||
_postBodyBuffer.append("<form action=\"").append(getAttachmentURLBase()).append("\">\n");
|
||||
_postBodyBuffer.append("<input type=\"hidden\" name=\"").append(ArchiveViewerBean.PARAM_BLOG);
|
||||
_postBodyBuffer.append("\" value=\"");
|
||||
@ -493,11 +563,11 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
else
|
||||
_postBodyBuffer.append("unknown");
|
||||
_postBodyBuffer.append("\" />\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" class=\"syndieEntryAttachmentsCell\">\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("<b>Attachments:</b> ");
|
||||
_postBodyBuffer.append("<select name=\"").append(ArchiveViewerBean.PARAM_ATTACHMENT).append("\">\n");
|
||||
_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];
|
||||
@ -510,53 +580,77 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_postBodyBuffer.append(", type ").append(sanitizeString(a.getMimeType())).append(")</option>\n");
|
||||
}
|
||||
_postBodyBuffer.append("</select>\n");
|
||||
_postBodyBuffer.append("<input type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
_postBodyBuffer.append("<input ").append(getClass("summDetailAttachmentDl")).append(" type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
}
|
||||
|
||||
if (_blogs.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Blog references:</b> ");
|
||||
_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 href=\"").append(getPageURL(new Hash(Base64.decode(b.hash)), b.tag, b.entryId, -1, -1, (_user != null ? _user.getShowExpanded() : false), (_user != null ? _user.getShowImages() : false)));
|
||||
_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("<b>External links:</b> ");
|
||||
_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 href=\"externallink.jsp?schema=");
|
||||
_postBodyBuffer.append(sanitizeURL(l.schema)).append("&location=");
|
||||
_postBodyBuffer.append(sanitizeURL(l.location));
|
||||
_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));
|
||||
_postBodyBuffer.append(" (").append(sanitizeString(l.schema)).append(")</a> ");
|
||||
_postBodyBuffer.append(getSpan("summDetailExternalNet")).append(" (").append(sanitizeString(l.schema)).append(")</span></a> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_addresses.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Addresses:</b>");
|
||||
_postBodyBuffer.append(getSpan("summDetailAddr")).append("Addresses:</span>");
|
||||
for (int i = 0; i < _addresses.size(); i++) {
|
||||
Address a = (Address)_addresses.get(i);
|
||||
_postBodyBuffer.append(" <a href=\"addaddress.jsp?schema=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.schema)).append("&location=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.location)).append("&name=");
|
||||
_postBodyBuffer.append(sanitizeURL(a.name));
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name));
|
||||
|
||||
String knownName = null;
|
||||
if (_user != null)
|
||||
knownName = _user.getPetNameDB().getNameByLocation(a.location);
|
||||
if (knownName != null) {
|
||||
_postBodyBuffer.append(' ').append(getSpan("summDetailAddrKnown"));
|
||||
_postBodyBuffer.append(sanitizeString(knownName)).append("</span>");
|
||||
} else {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailAddrLink")).append(" href=\"addresses.jsp?");
|
||||
if (a.schema != null)
|
||||
_postBodyBuffer.append("network=").append(sanitizeTagParam(a.schema)).append('&');
|
||||
if (a.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeTagParam(a.location)).append('&');
|
||||
if (a.name != null)
|
||||
_postBodyBuffer.append("name=").append(sanitizeTagParam(a.name)).append('&');
|
||||
if (a.protocol != null)
|
||||
_postBodyBuffer.append("protocol=").append(sanitizeTagParam(a.protocol)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_archives.size() > 0) {
|
||||
_postBodyBuffer.append("<b>Archives:</b>");
|
||||
_postBodyBuffer.append(getSpan("summDetailArchive")).append("Archives:</span>");
|
||||
for (int i = 0; i < _archives.size(); i++) {
|
||||
ArchiveRef a = (ArchiveRef)_archives.get(i);
|
||||
_postBodyBuffer.append(" <a href=\"").append(getArchiveURL(null, new SafeURL(a.locationSchema + "://" + a.location)));
|
||||
_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(sanitizeString(a.description));
|
||||
_postBodyBuffer.append(": ").append(getSpan("summDetailArchiveDesc")).append(sanitizeString(a.description)).append("</span>");
|
||||
if (null == _user.getPetNameDB().getNameByLocation(a.location)) {
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveBookmark")).append(" href=\"");
|
||||
_postBodyBuffer.append(getBookmarkURL(a.name, a.location, a.locationSchema, "syndiearchive"));
|
||||
_postBodyBuffer.append("\">bookmark it</a>");
|
||||
}
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
@ -564,21 +658,23 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
if (_entry != null) {
|
||||
List replies = _archive.getIndex().getReplies(_entry.getURI());
|
||||
if ( (replies != null) && (replies.size() > 0) ) {
|
||||
_postBodyBuffer.append("<b>Replies:</b> ");
|
||||
_postBodyBuffer.append(getSpan("summDetailReplies")).append("Replies:</span> ");
|
||||
for (int i = 0; i < replies.size(); i++) {
|
||||
BlogURI reply = (BlogURI)replies.get(i);
|
||||
_postBodyBuffer.append("<a href=\"");
|
||||
_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(" on ");
|
||||
_postBodyBuffer.append("</span> on ");
|
||||
_postBodyBuffer.append(getSpan("summDetailReplyDate"));
|
||||
_postBodyBuffer.append(getEntryDate(reply.getEntryId()));
|
||||
_postBodyBuffer.append("</a> ");
|
||||
_postBodyBuffer.append("</a></span> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />");
|
||||
}
|
||||
@ -586,21 +682,38 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) ) {
|
||||
_postBodyBuffer.append(" <a href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a><br />\n");
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailParent")).append(" href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">(view parent)</a><br />\n");
|
||||
}
|
||||
|
||||
_postBodyBuffer.append("</td>\n</form>\n</tr>\n");
|
||||
_postBodyBuffer.append("<!-- end of the post summary details -->\n");
|
||||
}
|
||||
_postBodyBuffer.append("</table>\n");
|
||||
}
|
||||
|
||||
public void receiveHeader(String header, String value) {
|
||||
//System.err.println("Receive header [" + header + "] = [" + value + "]");
|
||||
_headers.put(header, value);
|
||||
if (HEADER_PETNAME.equals(header)) {
|
||||
StringTokenizer tok = new StringTokenizer(value, "\t\n");
|
||||
if (tok.countTokens() != 4)
|
||||
return;
|
||||
String name = tok.nextToken();
|
||||
String net = tok.nextToken();
|
||||
String proto = tok.nextToken();
|
||||
String loc = tok.nextToken();
|
||||
Address a = new Address();
|
||||
a.name = sanitizeString(name, false);
|
||||
a.schema = sanitizeString(net, false);
|
||||
a.protocol = sanitizeString(proto, false);
|
||||
a.location = sanitizeString(loc, false);
|
||||
_addresses.add(a);
|
||||
} else {
|
||||
_headers.put(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveHeaderEnd() {
|
||||
_preBodyBuffer.append("<table width=\"100%\" border=\"0\">\n");
|
||||
_preBodyBuffer.append("<table ").append(getClass("overall")).append(" width=\"100%\" border=\"0\">\n");
|
||||
renderSubjectCell();
|
||||
renderMetaCell();
|
||||
renderPreBodyCell();
|
||||
@ -609,46 +722,76 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
public static final String HEADER_SUBJECT = "Subject";
|
||||
public static final String HEADER_BGCOLOR = "bgcolor";
|
||||
public static final String HEADER_IN_REPLY_TO = "InReplyTo";
|
||||
public static final String HEADER_STYLE = "Style";
|
||||
public static final String HEADER_PETNAME = "PetName";
|
||||
|
||||
private void renderSubjectCell() {
|
||||
_preBodyBuffer.append("<tr class=\"syndieEntrySubjectCell\"><td align=\"left\" valign=\"top\" class=\"syndieEntrySubjectCell\" width=\"400\"> ");
|
||||
_preBodyBuffer.append("<form action=\"index.jsp\">");
|
||||
_preBodyBuffer.append("<tr ").append(getClass("subject")).append(">");
|
||||
_preBodyBuffer.append("<td ").append(getClass("subject")).append(" align=\"left\" valign=\"top\" width=\"400\"> ");
|
||||
String subject = (String)_headers.get(HEADER_SUBJECT);
|
||||
if (subject == null)
|
||||
subject = "[no subject]";
|
||||
_preBodyBuffer.append(sanitizeString(subject));
|
||||
_preBodyBuffer.append("</td>\n");
|
||||
_preBodyBuffer.append(getSpan("subjectText")).append(sanitizeString(subject));
|
||||
_preBodyBuffer.append("</span></td>\n");
|
||||
}
|
||||
|
||||
private void renderPreBodyCell() {
|
||||
_preBodyBuffer.append("</form>");
|
||||
String bgcolor = (String)_headers.get(HEADER_BGCOLOR);
|
||||
if (_cutBody)
|
||||
_preBodyBuffer.append("<tr class=\"syndieEntrySummaryCell\"><td colspan=\"2\" align=\"left\" valign=\"top\" class=\"syndieEntrySummaryCell\" " + (bgcolor != null ? "bgcolor=\"" + sanitizeTagParam(bgcolor) + "\"" : "") + "\">");
|
||||
else
|
||||
_preBodyBuffer.append("<tr class=\"syndieEntryBodyCell\"><td colspan=\"2\" align=\"left\" valign=\"top\" class=\"syndieEntryBodyCell\" " + (bgcolor != null ? "bgcolor=\"" + sanitizeTagParam(bgcolor) + "\"" : "") + "\">");
|
||||
_preBodyBuffer.append("<tr ").append(getClass("body")).append(" >");
|
||||
_preBodyBuffer.append("<td colspan=\"2\" align=\"left\" valign=\"top\" ").append(getClass("body"));
|
||||
_preBodyBuffer.append((bgcolor != null ? " bgcolor=\"" + sanitizeTagParam(bgcolor) + "\"" : "") + ">");
|
||||
}
|
||||
|
||||
private void renderMetaCell() {
|
||||
String tags[] = (_entry != null ? _entry.getTags() : null);
|
||||
if ( (tags != null) && (tags.length > 0) )
|
||||
_preBodyBuffer.append("<form action=\"index.jsp\">");
|
||||
_preBodyBuffer.append("<td nowrap=\"true\" align=\"right\" valign=\"top\" class=\"syndieEntryMetaCell\">\n");
|
||||
_preBodyBuffer.append("<td nowrap=\"nowrap\" align=\"right\" valign=\"top\" ");
|
||||
_preBodyBuffer.append(getClass("meta")).append(">\n");
|
||||
|
||||
String knownName = null;
|
||||
if ( (_entry != null) && (_user != null) )
|
||||
knownName = _user.getPetNameDB().getNameByLocation(_entry.getURI().getKeyHash().toBase64());
|
||||
//if (knownName != null)
|
||||
// _preBodyBuffer.append("Pet name: ").append(sanitizeString(knownName)).append(" ");
|
||||
|
||||
BlogInfo info = null;
|
||||
if (_entry != null)
|
||||
info = _archive.getBlogInfo(_entry.getURI());
|
||||
if (info != null) {
|
||||
_preBodyBuffer.append("<a href=\"").append(getMetadataURL()).append("\">");
|
||||
String nameStr = info.getProperty("Name");
|
||||
if (nameStr == null)
|
||||
_preBodyBuffer.append("[no name]");
|
||||
else
|
||||
_preBodyBuffer.append(sanitizeString(nameStr));
|
||||
_preBodyBuffer.append("<a ").append(getClass("metaLink")).append(" href=\"").append(getMetadataURL()).append("\">");
|
||||
if (knownName != null) {
|
||||
_preBodyBuffer.append(getSpan("metaKnown")).append(sanitizeString(knownName)).append("</span>");
|
||||
} else {
|
||||
String nameStr = info.getProperty("Name");
|
||||
if (nameStr == null)
|
||||
_preBodyBuffer.append(getSpan("metaUnknown")).append("[no name]</span>");
|
||||
else
|
||||
_preBodyBuffer.append(getSpan("metaUnknown")).append(sanitizeString(nameStr)).append("</span>");
|
||||
}
|
||||
_preBodyBuffer.append("</a>");
|
||||
} else {
|
||||
_preBodyBuffer.append("[unknown blog]");
|
||||
_preBodyBuffer.append(getSpan("metaUnknown")).append("[unknown blog]</span>");
|
||||
}
|
||||
|
||||
|
||||
if ( (_user != null) && (_user.getAuthenticated()) && (_entry != null) ) {
|
||||
PetName pn = _user.getPetNameDB().get(knownName);
|
||||
if ( (pn == null) || (!pn.isMember("Favorites")) )
|
||||
_preBodyBuffer.append(" <input ").append(getClass("bookmark")).append(" type=\"submit\" name=\"action\" value=\"Bookmark blog\" />");
|
||||
if ( (pn == null) || (!pn.isMember("Ignore")) )
|
||||
_preBodyBuffer.append(" <input ").append(getClass("ignore")).append(" type=\"submit\" name=\"action\" value=\"Ignore blog\" />");
|
||||
else
|
||||
_preBodyBuffer.append(" <input ").append(getClass("unignore")).append(" type=\"submit\" name=\"action\" value=\"Unignore blog\" />");
|
||||
_preBodyBuffer.append(" <input type=\"hidden\" name=\"blog\" value=\"").append(_entry.getURI().getKeyHash().toBase64()).append("\" />");
|
||||
if (info != null)
|
||||
_preBodyBuffer.append(" <input type=\"hidden\" name=\"name\" value=\"").append(sanitizeTagParam(info.getProperty("Name"))).append("\" />");
|
||||
}
|
||||
|
||||
|
||||
if ( (tags != null) && (tags.length > 0) ) {
|
||||
_preBodyBuffer.append(" Tags: ");
|
||||
_preBodyBuffer.append("<select name=\"selector\">");
|
||||
_preBodyBuffer.append(getSpan("metaTags")).append(" Tags: ");
|
||||
_preBodyBuffer.append("<select ").append(getClass("metaTagList")).append(" name=\"selector\">");
|
||||
for (int i = 0; tags != null && i < tags.length; i++) {
|
||||
_preBodyBuffer.append("<option value=\"blogtag://");
|
||||
_preBodyBuffer.append(_entry.getURI().getKeyHash().toBase64());
|
||||
@ -666,7 +809,7 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
*/
|
||||
}
|
||||
_preBodyBuffer.append("</select>");
|
||||
_preBodyBuffer.append("<input type=\"submit\" value=\"View\" />\n");
|
||||
_preBodyBuffer.append("<input ").append(getClass("metaTagView")).append(" type=\"submit\" value=\"View\" /></span>\n");
|
||||
//_preBodyBuffer.append("</i>");
|
||||
}
|
||||
_preBodyBuffer.append(" ");
|
||||
@ -676,15 +819,18 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
_preBodyBuffer.append(" <a href=\"").append(getPageURL(sanitizeTagParam(inReplyTo))).append("\">In reply to</a>\n");
|
||||
*/
|
||||
|
||||
_preBodyBuffer.append(getSpan("metaDate"));
|
||||
if (_entry != null)
|
||||
_preBodyBuffer.append(getEntryDate(_entry.getURI().getEntryId()));
|
||||
else
|
||||
_preBodyBuffer.append(getEntryDate(new Date().getTime()));
|
||||
if ( (_user != null) && (_user.getAuthenticated()) )
|
||||
_preBodyBuffer.append(" <a href=\"").append(getPostURL(_user.getBlog(), true)).append("\">Reply</a>\n");
|
||||
_preBodyBuffer.append("</span>");
|
||||
|
||||
if ( (_user != null) && (_user.getAuthenticated()) ) {
|
||||
_preBodyBuffer.append(" <a ").append(getClass("replyLink"));
|
||||
_preBodyBuffer.append(" href=\"").append(getPostURL(_user.getBlog(), true)).append("\">Reply</a>\n");
|
||||
}
|
||||
_preBodyBuffer.append("\n</td>");
|
||||
if ( (tags != null) && (tags.length > 0) )
|
||||
_preBodyBuffer.append("</form>");
|
||||
_preBodyBuffer.append("</tr>\n");
|
||||
}
|
||||
|
||||
@ -694,9 +840,10 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(when));
|
||||
long dayBegin = _dateFormat.parse(str).getTime();
|
||||
return str + "." + (when - dayBegin);
|
||||
return str + " [" + (when - dayBegin) + "]";
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error formatting", pe);
|
||||
// wtf
|
||||
return "unknown";
|
||||
}
|
||||
@ -726,8 +873,12 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static final String sanitizeURL(String str) { return Base64.encode(DataHelper.getUTF8(str)); }
|
||||
public static final String sanitizeURL(String str) {
|
||||
if (str == null) return "";
|
||||
return Base64.encode(DataHelper.getUTF8(str));
|
||||
}
|
||||
public static final String sanitizeTagParam(String str) {
|
||||
if (str == null) return "";
|
||||
str = str.replace('&', '_'); // this should be &
|
||||
if (str.indexOf('\"') < 0)
|
||||
return sanitizeString(str);
|
||||
@ -735,8 +886,42 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
return sanitizeString(str);
|
||||
}
|
||||
|
||||
private String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : false); }
|
||||
private String getEntryURL(boolean showImages) {
|
||||
public static final String sanitizeXML(String orig) {
|
||||
if (orig == null) return "";
|
||||
if (orig.indexOf('&') < 0) return orig;
|
||||
StringBuffer rv = new StringBuffer(orig.length()+32);
|
||||
for (int i = 0; i < orig.length(); i++) {
|
||||
if (orig.charAt(i) == '&')
|
||||
rv.append("&");
|
||||
else
|
||||
rv.append(orig.charAt(i));
|
||||
}
|
||||
return rv.toString();
|
||||
}
|
||||
public static final String sanitizeXML(StringBuffer orig) {
|
||||
if (orig == null) return "";
|
||||
if (orig.indexOf("&") < 0) return orig.toString();
|
||||
for (int i = 0; i < orig.length(); i++) {
|
||||
if (orig.charAt(i) == '&') {
|
||||
orig = orig.replace(i, i+1, "&");
|
||||
i += "&".length();
|
||||
}
|
||||
}
|
||||
return orig.toString();
|
||||
}
|
||||
|
||||
private static final String STYLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||
public static String sanitizeStyle(String style) {
|
||||
if ( (style == null) || (style.trim().length() <= 0) ) return null;
|
||||
char c[] = style.toCharArray();
|
||||
for (int i = 0; i < c.length; i++)
|
||||
if (STYLE_CHARS.indexOf(c[i]) < 0)
|
||||
c[i] = '_';
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
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()) +
|
||||
@ -820,4 +1005,11 @@ public class HTMLRenderer extends EventReceiverImpl {
|
||||
+ "&schema=" + sanitizeTagParam(archiveLocation.getSchema())
|
||||
+ "&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);
|
||||
|
||||
}
|
||||
}
|
||||
|
310
apps/syndie/java/src/net/i2p/syndie/sml/RSSRenderer.java
Normal file
@ -0,0 +1,310 @@
|
||||
package net.i2p.syndie.sml;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RSSRenderer extends HTMLRenderer {
|
||||
|
||||
public RSSRenderer(I2PAppContext ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public void render(User user, Archive archive, EntryContainer entry, String urlPrefix, Writer out) throws IOException {
|
||||
if (entry == null) return;
|
||||
prepare(user, archive, entry, entry.getEntry().getText(), out, true, false);
|
||||
|
||||
out.write(" <item>\n");
|
||||
out.write(" <title>" + sanitizeXML(sanitizeString((String)_headers.get(HEADER_SUBJECT))) + "</title>\n");
|
||||
out.write(" <link>" + urlPrefix + sanitizeXML(getEntryURL()) + "</link>\n");
|
||||
out.write(" <guid isPermalink=\"false\">" + urlPrefix + entry.getURI().toString() + "</guid>\n");
|
||||
out.write(" <pubDate>" + getRFC822Date(entry.getURI().getEntryId()) + "</pubDate>\n");
|
||||
String author = user.getPetNameDB().getNameByLocation(entry.getURI().getKeyHash().toBase64());
|
||||
if (author == null) {
|
||||
BlogInfo info = archive.getBlogInfo(entry.getURI());
|
||||
if (info != null)
|
||||
author = info.getProperty(BlogInfo.NAME);
|
||||
}
|
||||
if (author == null)
|
||||
author = entry.getURI().getKeyHash().toBase64();
|
||||
out.write(" <author>" + sanitizeXML(sanitizeString(author)) + "@syndie.invalid</author>\n");
|
||||
String tags[] = entry.getTags();
|
||||
if (tags != null)
|
||||
for (int i = 0; i < tags.length; i++)
|
||||
out.write(" <category>" + sanitizeXML(sanitizeString(tags[i])) + "</category>\n");
|
||||
|
||||
out.write(" <description>" + sanitizeXML(_bodyBuffer.toString()) + "</description>\n");
|
||||
|
||||
//renderEnclosures(user, entry, urlPrefix, out);
|
||||
|
||||
out.write(" </item>\n");
|
||||
}
|
||||
|
||||
|
||||
public void receiveBold(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveItalic(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveUnderline(String text) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveHR() {
|
||||
if (!continueBody()) { return; }
|
||||
}
|
||||
public void receiveH1(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
public void receiveH2(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
public void receiveH3(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
public void receiveH4(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
public void receiveH5(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
public void receivePre(String body) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(body));
|
||||
}
|
||||
|
||||
public void receiveQuote(String text, String whoQuoted, String quoteLocationSchema, String quoteLocation) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveCode(String text, String codeLocationSchema, String codeLocation) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveImage(String alternateText, int attachmentId) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(alternateText));
|
||||
}
|
||||
public void receiveCut(String summaryText) {
|
||||
if (!continueBody()) { return; }
|
||||
_cutReached = true;
|
||||
if (_cutBody) {
|
||||
if ( (summaryText != null) && (summaryText.length() > 0) )
|
||||
_bodyBuffer.append(sanitizeString(summaryText));
|
||||
else
|
||||
_bodyBuffer.append("more inside...");
|
||||
} else {
|
||||
if (summaryText != null)
|
||||
_bodyBuffer.append(sanitizeString(summaryText));
|
||||
}
|
||||
}
|
||||
/** are we either before the cut or rendering without cutting? */
|
||||
protected boolean continueBody() {
|
||||
boolean rv = ( (!_cutReached) && (_bodyBuffer.length() <= _cutSize) ) || (!_cutBody);
|
||||
//if (!rv)
|
||||
// System.out.println("rv: " + rv + " Cut reached: " + _cutReached + " bodyBufferSize: " + _bodyBuffer.length() + " cutBody? " + _cutBody);
|
||||
if (!rv && !_cutReached) {
|
||||
// exceeded the allowed size
|
||||
_bodyBuffer.append("more inside...");
|
||||
_cutReached = true;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public void receiveNewline() {
|
||||
if (!continueBody()) { return; }
|
||||
if (true || (_lastNewlineAt >= _bodyBuffer.length()))
|
||||
_bodyBuffer.append("\n");
|
||||
else
|
||||
_lastNewlineAt = _bodyBuffer.length();
|
||||
}
|
||||
public void receiveBlog(String name, String hash, String tag, long entryId, List locations, String description) {
|
||||
byte blogData[] = Base64.decode(hash);
|
||||
if ( (blogData == null) || (blogData.length != Hash.HASH_LENGTH) )
|
||||
return;
|
||||
|
||||
Blog b = new Blog();
|
||||
b.name = name;
|
||||
b.hash = hash;
|
||||
b.tag = tag;
|
||||
b.entryId = entryId;
|
||||
b.locations = locations;
|
||||
if (!_blogs.contains(b))
|
||||
_blogs.add(b);
|
||||
|
||||
if (!continueBody()) { return; }
|
||||
if (hash == null) return;
|
||||
|
||||
Hash blog = new Hash(blogData);
|
||||
if ( (description != null) && (description.trim().length() > 0) ) {
|
||||
_bodyBuffer.append(sanitizeString(description));
|
||||
} else if ( (name != null) && (name.trim().length() > 0) ) {
|
||||
_bodyBuffer.append(sanitizeString(name));
|
||||
} else {
|
||||
_bodyBuffer.append("[view entry]");
|
||||
}
|
||||
}
|
||||
public void receiveArchive(String name, String description, String locationSchema, String location,
|
||||
String postingKey, String anchorText) {
|
||||
ArchiveRef a = new ArchiveRef();
|
||||
a.name = name;
|
||||
a.description = description;
|
||||
a.locationSchema = locationSchema;
|
||||
a.location = location;
|
||||
if (!_archives.contains(a))
|
||||
_archives.add(a);
|
||||
|
||||
if (!continueBody()) { return; }
|
||||
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
}
|
||||
public void receiveLink(String schema, String location, String text) {
|
||||
Link l = new Link();
|
||||
l.schema = schema;
|
||||
l.location = location;
|
||||
if (!_links.contains(l))
|
||||
_links.add(l);
|
||||
if (!continueBody()) { return; }
|
||||
if ( (schema == null) || (location == null) ) return;
|
||||
_bodyBuffer.append(sanitizeString(text));
|
||||
}
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText) {
|
||||
Address a = new Address();
|
||||
a.name = name;
|
||||
a.schema = schema;
|
||||
a.location = location;
|
||||
a.protocol = protocol;
|
||||
if (!_addresses.contains(a))
|
||||
_addresses.add(a);
|
||||
if (!continueBody()) { return; }
|
||||
if ( (schema == null) || (location == null) ) return;
|
||||
String knownName = null;
|
||||
if (_user != null)
|
||||
knownName = _user.getPetNameDB().getNameByLocation(location);
|
||||
if (knownName != null) {
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
} else {
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
}
|
||||
}
|
||||
public void receiveAttachment(int id, String anchorText) {
|
||||
if (!continueBody()) { return; }
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
}
|
||||
|
||||
// Mon, 03 Jun 2005 13:04:11 +0000
|
||||
private static final SimpleDateFormat _rfc822Date = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
private static final String getRFC822Date(long when) {
|
||||
synchronized (_rfc822Date) {
|
||||
return _rfc822Date.format(new Date(when));
|
||||
}
|
||||
}
|
||||
|
||||
private void renderEnclosures(User user, EntryContainer entry, String urlPrefix, Writer out) throws IOException {
|
||||
if (entry.getAttachments() != null) {
|
||||
for (int i = 0; i < _entry.getAttachments().length; i++) {
|
||||
Attachment a = _entry.getAttachments()[i];
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(getAttachmentURL(i))
|
||||
+ "\" length=\"" + a.getDataLength()
|
||||
+ "\" type=\"" + sanitizeTagParam(a.getMimeType()) + "\" syndietype=\"attachment\" />\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (_blogs.size() > 0) {
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
Blog b = (Blog)_blogs.get(i);
|
||||
out.write(" <enclosure url=\"" + urlPrefix +
|
||||
sanitizeXML(getPageURL(new Hash(Base64.decode(b.hash)), b.tag, b.entryId,
|
||||
-1, -1, (_user != null ? _user.getShowExpanded() : false),
|
||||
(_user != null ? _user.getShowImages() : false)))
|
||||
+ "\" length=\"1\" type=\"text/html\" syndietype=\"blog\" />\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (_links.size() > 0) {
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
Link l = (Link)_links.get(i);
|
||||
StringBuffer url = new StringBuffer(128);
|
||||
url.append("externallink.jsp?schema=");
|
||||
url.append(sanitizeURL(l.schema)).append("&location=");
|
||||
url.append(sanitizeURL(l.location));
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"link\" />\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (_addresses.size() > 0) {
|
||||
for (int i = 0; i < _addresses.size(); i++) {
|
||||
Address a = (Address)_addresses.get(i);
|
||||
|
||||
String knownName = null;
|
||||
if (_user != null)
|
||||
knownName = _user.getPetNameDB().getNameByLocation(a.location);
|
||||
if (knownName == 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(sanitizeTagParam(a.protocol));
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"address\" />\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_archives.size() > 0) {
|
||||
for (int i = 0; i < _archives.size(); i++) {
|
||||
ArchiveRef a = (ArchiveRef)_archives.get(i);
|
||||
String url = getArchiveURL(null, new SafeURL(a.locationSchema + "://" + a.location));
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"archive\" />\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (_entry != null) {
|
||||
List replies = _archive.getIndex().getReplies(_entry.getURI());
|
||||
if ( (replies != null) && (replies.size() > 0) ) {
|
||||
for (int i = 0; i < replies.size(); i++) {
|
||||
BlogURI reply = (BlogURI)replies.get(i);
|
||||
String url = getPageURL(reply.getKeyHash(), null, reply.getEntryId(), -1, -1, true, _user.getShowImages());
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"reply\" />\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String inReplyTo = (String)_headers.get(HEADER_IN_REPLY_TO);
|
||||
if ( (inReplyTo != null) && (inReplyTo.trim().length() > 0) ) {
|
||||
String url = getPageURL(sanitizeTagParam(inReplyTo));
|
||||
out.write(" <enclosure url=\"" + urlPrefix + sanitizeXML(url) + "\" length=\"1\" type=\"text/html\" syndietype=\"parent\" />\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveHeaderEnd() {}
|
||||
public void receiveEnd() {}
|
||||
|
||||
public static void main(String args[]) {
|
||||
test("");
|
||||
test("&");
|
||||
test("a&");
|
||||
test("&a");
|
||||
test("a&a");
|
||||
test("aa&aa");
|
||||
}
|
||||
private static final void test(String str) {
|
||||
StringBuffer t = new StringBuffer(str);
|
||||
String sanitized = sanitizeXML(t);
|
||||
System.out.println("[" + str + "] --> [" + sanitized + "]");
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package net.i2p.syndie.sml;
|
||||
import java.lang.String;
|
||||
import java.util.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Parse out the SML from the text, firing off info to the receiver whenever certain
|
||||
@ -12,6 +14,7 @@ import net.i2p.syndie.data.*;
|
||||
*
|
||||
*/
|
||||
public class SMLParser {
|
||||
private Log _log;
|
||||
private static final char TAG_BEGIN = '[';
|
||||
private static final char TAG_END = ']';
|
||||
private static final char LT = '<';
|
||||
@ -23,6 +26,10 @@ public class SMLParser {
|
||||
private static final char NL = '\n';
|
||||
private static final char CR = '\n';
|
||||
private static final char LF = '\f';
|
||||
|
||||
public SMLParser(I2PAppContext ctx) {
|
||||
_log = ctx.logManager().getLog(SMLParser.class);
|
||||
}
|
||||
|
||||
public void parse(String rawSML, EventReceiver receiver) {
|
||||
receiver.receiveBegin();
|
||||
@ -211,6 +218,7 @@ public class SMLParser {
|
||||
private static final String P_ADDRESS_NAME = "name";
|
||||
private static final String P_ADDRESS_LOCATION = "location";
|
||||
private static final String P_ADDRESS_SCHEMA = "schema";
|
||||
private static final String P_ADDRESS_PROTOCOL = "proto";
|
||||
private static final String P_ATTACHMENT_ID = "id";
|
||||
private static final String P_ARCHIVE_NAME = "name";
|
||||
private static final String P_ARCHIVE_DESCRIPTION = "description";
|
||||
@ -254,7 +262,7 @@ public class SMLParser {
|
||||
} else if (T_LINK.equals(tagName)) {
|
||||
receiver.receiveLink(getString(P_LINK_SCHEMA, attr), getString(P_LINK_LOCATION, attr), body);
|
||||
} else if (T_ADDRESS.equals(tagName)) {
|
||||
receiver.receiveAddress(getString(P_ADDRESS_NAME, attr), getString(P_ADDRESS_SCHEMA, attr), getString(P_ADDRESS_LOCATION, attr), body);
|
||||
receiver.receiveAddress(getString(P_ADDRESS_NAME, attr), getString(P_ADDRESS_SCHEMA, attr), getString(P_ADDRESS_PROTOCOL, attr), getString(P_ADDRESS_LOCATION, attr), body);
|
||||
} else if (T_H1.equals(tagName)) {
|
||||
receiver.receiveH1(body);
|
||||
} else if (T_H2.equals(tagName)) {
|
||||
@ -272,7 +280,8 @@ public class SMLParser {
|
||||
} else if (T_ATTACHMENT.equals(tagName)) {
|
||||
receiver.receiveAttachment((int)getLong(P_ATTACHMENT_ID, attr), body);
|
||||
} else {
|
||||
System.out.println("need to learn how to parse the tag [" + tagName + "]");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("need to learn how to parse the tag [" + tagName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,7 +390,7 @@ public class SMLParser {
|
||||
public void receiveArchive(String name, String description, String locationSchema, String location,
|
||||
String postingKey, String anchorText);
|
||||
public void receiveImage(String alternateText, int attachmentId);
|
||||
public void receiveAddress(String name, String schema, String location, String anchorText);
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText);
|
||||
public void receiveAttachment(int id, String anchorText);
|
||||
public void receiveBold(String text);
|
||||
public void receiveItalic(String text);
|
||||
@ -436,7 +445,8 @@ 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");
|
||||
}
|
||||
private static void test(String rawSML) {
|
||||
SMLParser parser = new SMLParser();
|
||||
parser.parse(rawSML, new EventReceiverImpl());
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
SMLParser parser = new SMLParser(ctx);
|
||||
parser.parse(rawSML, new EventReceiverImpl(ctx));
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
@ -17,14 +18,14 @@ import net.i2p.syndie.data.*;
|
||||
*/
|
||||
public class ArchiveServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String path = req.getPathInfo();
|
||||
if ( (path == null) || (path.trim().length() <= 1) ) {
|
||||
renderRootIndex(resp);
|
||||
return;
|
||||
} else if (path.endsWith(Archive.INDEX_FILE)) {
|
||||
renderSummary(resp);
|
||||
} else if (path.endsWith("export.zip")) {
|
||||
} else if (path.indexOf("export.zip") != -1) {
|
||||
ExportServlet.export(req, resp);
|
||||
} else {
|
||||
String blog = getBlog(path);
|
||||
@ -89,12 +90,18 @@ public class ArchiveServlet extends HttpServlet {
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static final String HEADER_EXPORT_CAPABLE = "X-Syndie-Export-Capable";
|
||||
|
||||
private void renderSummary(HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain;charset=utf-8");
|
||||
//resp.setCharacterEncoding("UTF-8");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
ArchiveIndex index = BlogManager.instance().getArchive().getIndex();
|
||||
out.write(DataHelper.getUTF8(index.toString()));
|
||||
byte[] indexUTF8 = DataHelper.getUTF8(index.toString());
|
||||
resp.setHeader(HEADER_EXPORT_CAPABLE, "true");
|
||||
Hash hash = I2PAppContext.getGlobalContext().sha().calculateHash(indexUTF8);
|
||||
resp.setHeader("ETag", "\"" + hash.toBase64() + "\"");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
out.write(indexUTF8);
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetName;
|
||||
import net.i2p.client.naming.PetNameDB;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
@ -20,25 +22,6 @@ public class ArchiveViewerBean {
|
||||
else
|
||||
return HTMLRenderer.sanitizeString(info.getProperty("Name"));
|
||||
}
|
||||
public static String getEntryTitle(String keyHash, long entryId) {
|
||||
String name = getBlogName(keyHash);
|
||||
return getEntryTitleDate(name, entryId);
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.UK);
|
||||
public static final String getEntryTitleDate(String blogName, long when) {
|
||||
synchronized (_dateFormat) {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(when));
|
||||
long dayBegin = _dateFormat.parse(str).getTime();
|
||||
return blogName + ":<br /> <i>" + str + "-" + (when - dayBegin) + "</i>";
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
// wtf
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** base64 encoded hash of the blog's public key, or null for no filtering by blog */
|
||||
public static final String PARAM_BLOG = "blog";
|
||||
@ -91,23 +74,22 @@ public class ArchiveViewerBean {
|
||||
BlogManager.instance().saveUser(user);
|
||||
}
|
||||
|
||||
out.write("<select name=\"");
|
||||
out.write("<select class=\"b_selector\" name=\"");
|
||||
out.write(PARAM_SELECTOR);
|
||||
out.write("\">");
|
||||
out.write("<option value=\"");
|
||||
out.write(getDefaultSelector(user, parameters));
|
||||
out.write("\">Default blog filter</option>\n");
|
||||
out.write("\">");
|
||||
out.write("<option value=\"");
|
||||
out.write(SEL_ALL);
|
||||
out.write("\">All posts from all blogs</option>\n");
|
||||
|
||||
Map groups = null;
|
||||
List groups = null;
|
||||
if (user != null)
|
||||
groups = user.getBlogGroups();
|
||||
groups = user.getPetNameDB().getGroups();
|
||||
if (groups != null) {
|
||||
for (Iterator iter = groups.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
String name = (String)groups.get(i);
|
||||
out.write("<option value=\"group://" + Base64.encode(DataHelper.getUTF8(name)) + "\">" +
|
||||
"Group: " + HTMLRenderer.sanitizeString(name) + "</option>\n");
|
||||
}
|
||||
@ -118,11 +100,21 @@ public class ArchiveViewerBean {
|
||||
|
||||
for (int i = 0; i < index.getNewestBlogCount(); i++) {
|
||||
Hash cur = index.getNewestBlog(i);
|
||||
String knownName = user.getPetNameDB().getNameByLocation(cur.toBase64());
|
||||
PetName pn = null;
|
||||
if (knownName != null) {
|
||||
pn = user.getPetNameDB().get(knownName);
|
||||
knownName = pn.getName();
|
||||
}
|
||||
if ( (pn != null) && (pn.isMember("Ignore")) )
|
||||
continue;
|
||||
String blog = Base64.encode(cur.getData());
|
||||
out.write("<option value=\"blog://" + blog + "\">");
|
||||
out.write("New blog: ");
|
||||
BlogInfo info = archive.getBlogInfo(cur);
|
||||
String name = info.getProperty(BlogInfo.NAME);
|
||||
String name = knownName;
|
||||
if ( (name == null) && (info != null) )
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
if (name != null)
|
||||
name = HTMLRenderer.sanitizeString(name);
|
||||
else
|
||||
@ -131,24 +123,43 @@ public class ArchiveViewerBean {
|
||||
out.write("</option>\n");
|
||||
}
|
||||
|
||||
List allTags = new ArrayList();
|
||||
////List allTags = new ArrayList();
|
||||
// perhaps sort this by name (even though it isnt unique...)
|
||||
Set blogs = index.getUniqueBlogs();
|
||||
for (Iterator iter = blogs.iterator(); iter.hasNext(); ) {
|
||||
Hash cur = (Hash)iter.next();
|
||||
String knownName = user.getPetNameDB().getNameByLocation(cur.toBase64());
|
||||
PetName pn = null;
|
||||
if (knownName != null) {
|
||||
pn = user.getPetNameDB().get(knownName);
|
||||
knownName = pn.getName();
|
||||
}
|
||||
if ( (pn != null) && (pn.isMember("Ignore")) )
|
||||
continue;
|
||||
|
||||
String blog = Base64.encode(cur.getData());
|
||||
out.write("<option value=\"blog://");
|
||||
out.write(blog);
|
||||
out.write("\">");
|
||||
BlogInfo info = archive.getBlogInfo(cur);
|
||||
String name = info.getProperty(BlogInfo.NAME);
|
||||
String name = knownName;
|
||||
if ( (name == null) && (info != null) )
|
||||
name = info.getProperty(BlogInfo.NAME);
|
||||
if (name != null)
|
||||
name = HTMLRenderer.sanitizeString(name);
|
||||
else
|
||||
name = Base64.encode(cur.getData());
|
||||
out.write(name);
|
||||
out.write("- all posts</option>\n");
|
||||
if (info != null) {
|
||||
int howMany = index.getBlogEntryCount(info.getKey().calculateHash());
|
||||
if (howMany == 1)
|
||||
out.write(" [1 post]");
|
||||
else
|
||||
out.write(" [" + howMany + " posts]");
|
||||
}
|
||||
out.write("</option>\n");
|
||||
|
||||
/*
|
||||
List tags = index.getBlogTags(cur);
|
||||
for (int j = 0; j < tags.size(); j++) {
|
||||
String tag = (String)tags.get(j);
|
||||
@ -190,7 +201,9 @@ public class ArchiveViewerBean {
|
||||
out.write(tag);
|
||||
out.write(""</option>\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
for (int i = 0; i < allTags.size(); i++) {
|
||||
String tag = (String)allTags.get(i);
|
||||
out.write("<option value=\"tag://");
|
||||
@ -199,6 +212,7 @@ public class ArchiveViewerBean {
|
||||
out.write(tag);
|
||||
out.write(""</option>\n");
|
||||
}
|
||||
*/
|
||||
out.write("</select>");
|
||||
|
||||
int numPerPage = getInt(parameters, PARAM_NUM_PER_PAGE, 5);
|
||||
@ -224,10 +238,12 @@ public class ArchiveViewerBean {
|
||||
String blogStr = getString(parameters, PARAM_BLOG);
|
||||
Hash blog = null;
|
||||
if (blogStr != null) blog = new Hash(Base64.decode(blogStr));
|
||||
if ( (blog != null) && (blog.getData() == null) ) blog = null;
|
||||
String tag = getString(parameters, PARAM_TAG);
|
||||
if (tag != null) tag = DataHelper.getUTF8(Base64.decode(tag));
|
||||
|
||||
long entryId = -1;
|
||||
if (blogStr != null) {
|
||||
if (blog != null) {
|
||||
String entryIdStr = getString(parameters, PARAM_ENTRY);
|
||||
try {
|
||||
entryId = Long.parseLong(entryIdStr);
|
||||
@ -237,6 +253,14 @@ public class ArchiveViewerBean {
|
||||
if (group != null) group = DataHelper.getUTF8(Base64.decode(group));
|
||||
|
||||
String sel = getString(parameters, PARAM_SELECTOR);
|
||||
|
||||
if (getString(parameters, "action") != null) {
|
||||
tag = null;
|
||||
blog = null;
|
||||
sel = null;
|
||||
group = null;
|
||||
}
|
||||
|
||||
if ( (sel == null) && (blog == null) && (group == null) && (tag == null) )
|
||||
sel = getDefaultSelector(user, parameters);
|
||||
if (sel != null) {
|
||||
@ -275,12 +299,21 @@ public class ArchiveViewerBean {
|
||||
if (selector != null) {
|
||||
if (selector.startsWith(SEL_BLOG)) {
|
||||
String blogStr = selector.substring(SEL_BLOG.length());
|
||||
System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "]");
|
||||
blog = new Hash(Base64.decode(blogStr));
|
||||
//System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "]");
|
||||
byte h[] = Base64.decode(blogStr);
|
||||
if (h != null)
|
||||
blog = new Hash(h);
|
||||
//else
|
||||
// System.out.println("blog string does not decode properly: [" + blogStr + "]");
|
||||
} else if (selector.startsWith(SEL_BLOGTAG)) {
|
||||
int tagStart = selector.lastIndexOf('/');
|
||||
String blogStr = selector.substring(SEL_BLOGTAG.length(), tagStart);
|
||||
blog = new Hash(Base64.decode(blogStr));
|
||||
if (blog.getData() == null) {
|
||||
System.out.println("Blog string [" + blogStr + "] does not decode");
|
||||
blog = null;
|
||||
return;
|
||||
}
|
||||
tag = selector.substring(tagStart+1);
|
||||
String origTag = tag;
|
||||
byte rawDecode[] = null;
|
||||
@ -288,7 +321,7 @@ public class ArchiveViewerBean {
|
||||
rawDecode = Base64.decode(tag);
|
||||
tag = DataHelper.getUTF8(rawDecode);
|
||||
}
|
||||
System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "] tag: [" + tag + "]");
|
||||
//System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "] tag: [" + tag + "]");
|
||||
if (false && tag != null) {
|
||||
StringBuffer b = new StringBuffer(tag.length()*2);
|
||||
for (int j = 0; j < tag.length(); j++) {
|
||||
@ -301,7 +334,7 @@ public class ArchiveViewerBean {
|
||||
for (int j = 0; j < origTag.length(); j++) {
|
||||
b.append((int)origTag.charAt(j)).append(' ');
|
||||
}
|
||||
System.out.println("selected tag: " + b.toString());
|
||||
//System.out.println("selected tag: " + b.toString());
|
||||
}
|
||||
} else if (selector.startsWith(SEL_TAG)) {
|
||||
tag = selector.substring(SEL_TAG.length());
|
||||
@ -310,7 +343,7 @@ public class ArchiveViewerBean {
|
||||
rawDecode = Base64.decode(tag);
|
||||
tag = DataHelper.getUTF8(rawDecode);
|
||||
}
|
||||
System.out.println("Selector [" + selector + "] tag: [" + tag + "]");
|
||||
//System.out.println("Selector [" + selector + "] tag: [" + tag + "]");
|
||||
if (false && tag != null) {
|
||||
StringBuffer b = new StringBuffer(tag.length()*2);
|
||||
for (int j = 0; j < tag.length(); j++) {
|
||||
@ -319,7 +352,7 @@ public class ArchiveViewerBean {
|
||||
b.append('.').append((int)rawDecode[j]);
|
||||
b.append(' ');
|
||||
}
|
||||
System.out.println("selected tag: " + b.toString());
|
||||
//System.out.println("selected tag: " + b.toString());
|
||||
}
|
||||
} else if (selector.startsWith(SEL_ENTRY)) {
|
||||
int entryStart = selector.lastIndexOf('/');
|
||||
@ -327,12 +360,16 @@ public class ArchiveViewerBean {
|
||||
String entryStr = selector.substring(entryStart+1);
|
||||
try {
|
||||
entry = Long.parseLong(entryStr);
|
||||
blog = new Hash(Base64.decode(blogStr));
|
||||
System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "] entry: [" + entry + "]");
|
||||
Hash h = new Hash(Base64.decode(blogStr));
|
||||
if (h.getData() != null)
|
||||
blog = h;
|
||||
//else
|
||||
// System.out.println("Blog does not decode [" + blogStr + "]");
|
||||
//System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "] entry: [" + entry + "]");
|
||||
} catch (NumberFormatException nfe) {}
|
||||
} else if (selector.startsWith(SEL_GROUP)) {
|
||||
group = DataHelper.getUTF8(Base64.decode(selector.substring(SEL_GROUP.length())));
|
||||
System.out.println("Selector [" + selector + "] group: [" + group + "]");
|
||||
//System.out.println("Selector [" + selector + "] group: [" + group + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -345,10 +382,10 @@ public class ArchiveViewerBean {
|
||||
archive.regenerateIndex();
|
||||
ArchiveIndex index = archive.getIndex();
|
||||
List entries = pickEntryURIs(user, index, blog, tag, entryId, group);
|
||||
System.out.println("Searching for " + blog + "/" + tag + "/" + entryId + "/" + pageNum + "/" + numPerPage + "/" + group);
|
||||
System.out.println("Entry URIs: " + entries);
|
||||
//System.out.println("Searching for " + blog + "/" + tag + "/" + entryId + "/" + pageNum + "/" + numPerPage + "/" + group);
|
||||
//System.out.println("Entry URIs: " + entries);
|
||||
|
||||
HTMLRenderer renderer = new HTMLRenderer();
|
||||
HTMLRenderer renderer = new HTMLRenderer(I2PAppContext.getGlobalContext());
|
||||
int start = pageNum * numPerPage;
|
||||
int end = start + numPerPage;
|
||||
int pages = 1;
|
||||
@ -366,31 +403,29 @@ public class ArchiveViewerBean {
|
||||
pages = entries.size() / numPerPage;
|
||||
if (numPerPage * pages < entries.size())
|
||||
pages++;
|
||||
out.write("<i>");
|
||||
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);
|
||||
System.out.println("prevURL: " + prevURL);
|
||||
out.write(" <a href=\"" + prevURL + "\"><<</a>");
|
||||
//System.out.println("prevURL: " + prevURL);
|
||||
out.write(" <a class=\"b_selectorPrevMore\" href=\"" + prevURL + "\"><<</a>");
|
||||
} else {
|
||||
out.write(" << ");
|
||||
out.write(" <span class=\"b_selectorPrevNone\"><<</span> ");
|
||||
}
|
||||
out.write("Page " + (pageNum+1) + " of " + pages);
|
||||
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);
|
||||
System.out.println("nextURL: " + nextURL);
|
||||
out.write(" <a href=\"" + nextURL + "\">>></a>");
|
||||
//System.out.println("nextURL: " + nextURL);
|
||||
out.write(" <a class=\"b_selectorNextMore\" href=\"" + nextURL + "\">>></a>");
|
||||
} else {
|
||||
out.write(" >>");
|
||||
out.write(" <span class=\"b_selectorNextNone\">>></span>");
|
||||
}
|
||||
out.write("</i>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,7 +453,7 @@ public class ArchiveViewerBean {
|
||||
out.write(afterPagination);
|
||||
|
||||
if (entries.size() <= 0) end = -1;
|
||||
System.out.println("Entries.size: " + entries.size() + " start=" + start + " end=" + end);
|
||||
//System.out.println("Entries.size: " + entries.size() + " start=" + start + " end=" + end);
|
||||
for (int i = start; i < end; i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
EntryContainer c = archive.getEntry(uri);
|
||||
@ -434,7 +469,9 @@ public class ArchiveViewerBean {
|
||||
}
|
||||
}
|
||||
|
||||
private static List pickEntryURIs(User user, ArchiveIndex index, Hash blog, String tag, long entryId, String group) {
|
||||
public static List pickEntryURIs(User user, ArchiveIndex index, Hash blog, String tag, long entryId, String group) {
|
||||
if ( (blog != null) && ( (blog.getData() == null) || (blog.getData().length != Hash.HASH_LENGTH) ) )
|
||||
blog = null;
|
||||
List rv = new ArrayList(16);
|
||||
if ( (blog != null) && (entryId >= 0) ) {
|
||||
rv.add(new BlogURI(blog, entryId));
|
||||
@ -444,7 +481,7 @@ public class ArchiveViewerBean {
|
||||
if ( (group != null) && (user != null) ) {
|
||||
List selectors = (List)user.getBlogGroups().get(group);
|
||||
if (selectors != null) {
|
||||
System.out.println("Selectors for group " + group + ": " + selectors);
|
||||
//System.out.println("Selectors for group " + group + ": " + selectors);
|
||||
for (int i = 0; i < selectors.size(); i++) {
|
||||
String sel = (String)selectors.get(i);
|
||||
Selector s = new Selector(sel);
|
||||
@ -453,13 +490,57 @@ public class ArchiveViewerBean {
|
||||
else
|
||||
index.selectMatchesOrderByEntryId(rv, s.blog, s.tag);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.get(name);
|
||||
if ("syndie".equals(pn.getNetwork()) && "syndieblog".equals(pn.getProtocol()) && pn.isMember(group)) {
|
||||
byte pnLoc[] = Base64.decode(pn.getLocation());
|
||||
if (pnLoc != null) {
|
||||
Hash pnHash = new Hash(pnLoc);
|
||||
index.selectMatchesOrderByEntryId(rv, pnHash, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(rv);
|
||||
if (rv.size() > 0)
|
||||
return rv;
|
||||
}
|
||||
index.selectMatchesOrderByEntryId(rv, blog, tag);
|
||||
filterIgnored(user, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static void filterIgnored(User user, List uris) {
|
||||
for (int i = 0; i < uris.size(); i++) {
|
||||
BlogURI uri = (BlogURI)uris.get(i);
|
||||
Hash k = uri.getKeyHash();
|
||||
if (k == null) continue;
|
||||
String pname = user.getPetNameDB().getNameByLocation(k.toBase64());
|
||||
if (pname != null) {
|
||||
PetName pn = user.getPetNameDB().get(pname);
|
||||
if ( (pn != null) && (pn.isMember("Ignore")) ) {
|
||||
uris.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sort(List uris) {
|
||||
TreeMap ordered = new TreeMap();
|
||||
while (uris.size() > 0) {
|
||||
BlogURI uri = (BlogURI)uris.remove(0);
|
||||
int off = 0;
|
||||
while (ordered.containsKey(new Long(0 - off - uri.getEntryId())))
|
||||
off++;
|
||||
ordered.put(new Long(0-off-uri.getEntryId()), uri);
|
||||
}
|
||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
||||
uris.add(iter.next());
|
||||
}
|
||||
|
||||
public static final String getString(Map parameters, String param) {
|
||||
if ( (parameters == null) || (parameters.get(param) == null) )
|
||||
return null;
|
||||
@ -539,6 +620,17 @@ public class ArchiveViewerBean {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
public static final boolean getAttachmentShouldShowInline(Map parameters) {
|
||||
Attachment a = getAttachment(parameters);
|
||||
if (a == null)
|
||||
return true;
|
||||
String mime = a.getMimeType();
|
||||
if ( (mime != null) && ((mime.startsWith("image/") || mime.startsWith("text/plain"))) )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final int getAttachmentContentLength(Map parameters) {
|
||||
Attachment a = getAttachment(parameters);
|
||||
if (a != null)
|
||||
@ -547,6 +639,14 @@ public class ArchiveViewerBean {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static final String getAttachmentFilename(Map parameters) {
|
||||
Attachment a = getAttachment(parameters);
|
||||
if (a != null)
|
||||
return a.getName();
|
||||
else
|
||||
return "attachment.dat";
|
||||
}
|
||||
|
||||
private static final Attachment getAttachment(Map parameters) {
|
||||
String blogStr = getString(parameters, PARAM_BLOG);
|
||||
Hash blog = null;
|
||||
@ -569,10 +669,63 @@ public class ArchiveViewerBean {
|
||||
}
|
||||
|
||||
private static void renderInvalidAttachment(Map parameters, OutputStream out) throws IOException {
|
||||
out.write(DataHelper.getUTF8("<b>No such entry, or no such attachment</b>"));
|
||||
out.write(DataHelper.getUTF8("<span class=\"b_msgErr\">No such entry, or no such attachment</span>"));
|
||||
}
|
||||
|
||||
public static void renderMetadata(Map parameters, Writer out) throws IOException {
|
||||
private static String getURL(String uri, Map parameters) {
|
||||
StringBuffer rv = new StringBuffer(128);
|
||||
rv.append(uri);
|
||||
rv.append('?');
|
||||
if (parameters != null) {
|
||||
for (Iterator iter = parameters.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String vals[] = getStrings(parameters, key);
|
||||
// we are already looking at the page with the given parameters, no need to further sanitize
|
||||
if ( (key != null) && (vals != null) )
|
||||
for (int i = 0; i < vals.length; i++)
|
||||
rv.append(key).append('=').append(vals[i]).append('&');
|
||||
}
|
||||
}
|
||||
return rv.toString();
|
||||
}
|
||||
|
||||
private static void updateMetadata(User viewer, Map parameters, Writer out) throws IOException {
|
||||
if ( (viewer == null) || (!viewer.getAuthenticated()) )
|
||||
return;
|
||||
String blogStr = getString(parameters, PARAM_BLOG);
|
||||
if (blogStr != null) {
|
||||
Hash blog = new Hash(Base64.decode(blogStr));
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
BlogInfo info = archive.getBlogInfo(blog);
|
||||
if (info != null) {
|
||||
boolean isUser = viewer.getBlog().equals(info.getKey().calculateHash());
|
||||
if (!isUser)
|
||||
return;
|
||||
Properties toSave = new Properties();
|
||||
String existing[] = info.getProperties();
|
||||
for (int i = 0; i < existing.length; i++) {
|
||||
String newVal = getString(parameters, existing[i]);
|
||||
if ( (newVal != null) && (newVal.length() > 0) )
|
||||
toSave.setProperty(existing[i], newVal.trim());
|
||||
else
|
||||
toSave.setProperty(existing[i], info.getProperty(existing[i]));
|
||||
}
|
||||
boolean saved = BlogManager.instance().updateMetadata(viewer, blog, toSave);
|
||||
if (saved)
|
||||
out.write("<p><em class=\"b_msgOk\">Blog metadata saved</em></p>\n");
|
||||
else
|
||||
out.write("<p><em class=\"b_msgErr\">Blog metadata could not be saved</em></p>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currentURI URI of the with current page without any parameters tacked on
|
||||
*/
|
||||
public static void renderMetadata(User viewer, String currentURI, Map parameters, Writer out) throws IOException {
|
||||
if (parameters.get("action") != null) {
|
||||
updateMetadata(viewer, parameters, out);
|
||||
}
|
||||
String blogStr = getString(parameters, PARAM_BLOG);
|
||||
if (blogStr != null) {
|
||||
Hash blog = new Hash(Base64.decode(blogStr));
|
||||
@ -582,44 +735,59 @@ public class ArchiveViewerBean {
|
||||
out.write("Blog " + blog.toBase64() + " does not exist");
|
||||
return;
|
||||
}
|
||||
boolean isUser = ( (viewer != null) && (viewer.getAuthenticated()) && (viewer.getBlog().equals(info.getKey().calculateHash())) );
|
||||
String props[] = info.getProperties();
|
||||
out.write("<table border=\"0\">");
|
||||
if (isUser) {
|
||||
out.write("<form action=\"" + getURL(currentURI, parameters) + "\" method=\"GET\">\n");
|
||||
out.write("<input type=\"hidden\" name=\"submit_blog\" value=\"" + blog.toBase64() + "\" />\n");
|
||||
}
|
||||
out.write("<table class=\"b_meta\" border=\"0\">");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (props[i].equals(BlogInfo.OWNER_KEY)) {
|
||||
out.write("<tr><td><b>Blog:</b></td><td>");
|
||||
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("<a href=\"" + blogURL + "\">" + Base64.encode(blog.getData()) + "</td></tr>\n");
|
||||
out.write("<td class=\"b_metaBlog\"><a class=\"b_metaBlog\" href=\"" + blogURL + "\">" + Base64.encode(blog.getData()) + "</td></tr>\n");
|
||||
} else if (props[i].equals(BlogInfo.SIGNATURE)) {
|
||||
continue;
|
||||
} else if (props[i].equals(BlogInfo.POSTERS)) {
|
||||
SigningPublicKey keys[] = info.getPosters();
|
||||
if ( (keys != null) && (keys.length > 0) ) {
|
||||
out.write("<tr><td><b>Allowed authors:</b></td><td>");
|
||||
out.write("<tr class=\"b_metaAuthor\"><td class=\"b_metaAuthor\"><span class=\"b_metaAuthor\">Allowed authors:</span></td>");
|
||||
out.write("<td class=\"b_metaAuthor\">");
|
||||
for (int j = 0; j < keys.length; j++) {
|
||||
out.write(keys[j].calculateHash().toBase64());
|
||||
out.write("<span class=\"b_metaAuthor\">" + keys[j].calculateHash().toBase64() + "</span>");
|
||||
if (j + 1 < keys.length)
|
||||
out.write("<br />\n");
|
||||
}
|
||||
out.write("</td></tr>\n");
|
||||
}
|
||||
} else {
|
||||
out.write("<tr><td>" + HTMLRenderer.sanitizeString(props[i]) + ":</td><td>" +
|
||||
HTMLRenderer.sanitizeString(info.getProperty(props[i])) + "</td></tr>\n");
|
||||
String field = HTMLRenderer.sanitizeString(props[i]);
|
||||
String val = HTMLRenderer.sanitizeString(info.getProperty(props[i]));
|
||||
out.write("<tr class=\"b_metaField\"><td class=\"b_metaField\"><span class=\"b_metaField\">" + field
|
||||
+ ":</span></td><td class=\"b_metaValue\"><span class=\"b_metaValue\">" + val + "</span></td></tr>\n");
|
||||
|
||||
if (isUser && (!field.equals("Edition")))
|
||||
out.write("<tr class=\"b_metaField\"><td> </td><td class=\"b_metaValue\"><input type=\"text\" name=\""
|
||||
+ HTMLRenderer.sanitizeTagParam(props[i]) + "\" value=\""
|
||||
+ HTMLRenderer.sanitizeTagParam(info.getProperty(props[i])) + "\" size=\"40\" ></td></tr>");
|
||||
}
|
||||
}
|
||||
List tags = BlogManager.instance().getArchive().getIndex().getBlogTags(blog);
|
||||
if ( (tags != null) && (tags.size() > 0) ) {
|
||||
out.write("<tr><td>Known tags:</td><td>");
|
||||
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 href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, false, false) + "\">" +
|
||||
out.write("<a class=\"b_metaTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, false, false) + "\">" +
|
||||
HTMLRenderer.sanitizeString(tag) + "</a> ");
|
||||
}
|
||||
out.write("</td></tr>");
|
||||
}
|
||||
if (isUser)
|
||||
out.write("<tr class=\"b_metaField\"><td colspan=\"2\" class=\"b_metaField\"><input type=\"submit\" name=\"action\" value=\"Save changes\" class=\"b_metaSave\" /></td></tr>\n");
|
||||
out.write("</table>");
|
||||
} else {
|
||||
out.write("Blog not specified");
|
||||
out.write("<span class=\"b_metaMsgErr\">Blog not specified</span>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,98 @@ import net.i2p.syndie.data.*;
|
||||
*/
|
||||
public class ExportServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
export(req, resp);
|
||||
}
|
||||
|
||||
public static void export(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String meta[] = req.getParameterValues("meta");
|
||||
String entries[] = req.getParameterValues("entry");
|
||||
try {
|
||||
doExport(req, resp);
|
||||
} catch (ServletException se) {
|
||||
se.printStackTrace();
|
||||
throw se;
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
private static void doExport(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String meta[] = null;
|
||||
String entries[] = null;
|
||||
String type = req.getHeader("Content-Type");
|
||||
if ( (type == null) || (type.indexOf("boundary") == -1) ) {
|
||||
// it has to be POSTed with the request, name=value pairs. the export servlet doesn't allow any
|
||||
// free form fields, so no worry about newlines, so lets parse 'er up
|
||||
List metaList = new ArrayList();
|
||||
List entryList = new ArrayList();
|
||||
StringBuffer key = new StringBuffer();
|
||||
StringBuffer val = null;
|
||||
String lenStr = req.getHeader("Content-length");
|
||||
int len = -1;
|
||||
if (lenStr != null)
|
||||
try { len = Integer.valueOf(lenStr).intValue(); } catch (NumberFormatException nfe) {}
|
||||
|
||||
int read = 0;
|
||||
int c = 0;
|
||||
InputStream in = req.getInputStream();
|
||||
while ( (len == -1) || (read < len) ){
|
||||
c = in.read();
|
||||
if ( (c == '=') && (val == null) ) {
|
||||
val = new StringBuffer(128);
|
||||
} else if ( (c == -1) || (c == '&') ) {
|
||||
String k = (key == null ? "" : key.toString());
|
||||
String v = (val == null ? "" : val.toString());
|
||||
if ("meta".equals(k))
|
||||
metaList.add(v.trim());
|
||||
else if ("entry".equals(k))
|
||||
entryList.add(v.trim());
|
||||
key.setLength(0);
|
||||
val = null;
|
||||
// no newlines in the export servlet
|
||||
if (c == -1)
|
||||
break;
|
||||
} else {
|
||||
if (val == null)
|
||||
key.append((char)c);
|
||||
else
|
||||
val.append((char)c);
|
||||
}
|
||||
read++;
|
||||
}
|
||||
if (metaList != null) {
|
||||
meta = new String[metaList.size()];
|
||||
for (int i = 0; i < metaList.size(); i++)
|
||||
meta[i] = (String)metaList.get(i);
|
||||
}
|
||||
if (entryList != null) {
|
||||
entries = new String[entryList.size()];
|
||||
for (int i = 0; i < entryList.size(); i++)
|
||||
entries[i] = (String)entryList.get(i);
|
||||
}
|
||||
} else {
|
||||
meta = req.getParameterValues("meta");
|
||||
entries = req.getParameterValues("entry");
|
||||
}
|
||||
resp.setContentType("application/x-syndie-zip");
|
||||
resp.setStatus(200);
|
||||
OutputStream out = resp.getOutputStream();
|
||||
ZipOutputStream zo = new ZipOutputStream(out);
|
||||
|
||||
if (false) {
|
||||
StringBuffer bbuf = new StringBuffer(1024);
|
||||
bbuf.append("meta: ");
|
||||
if (meta != null)
|
||||
for (int i = 0; i < meta.length; i++)
|
||||
bbuf.append(meta[i]).append(", ");
|
||||
bbuf.append("entries: ");
|
||||
if (entries != null)
|
||||
for (int i = 0; i < entries.length; i++)
|
||||
bbuf.append(entries[i]).append(", ");
|
||||
System.out.println(bbuf.toString());
|
||||
}
|
||||
|
||||
ZipOutputStream zo = null;
|
||||
if ( (meta != null) && (entries != null) && (meta.length + entries.length > 0) )
|
||||
zo = new ZipOutputStream(out);
|
||||
|
||||
List metaFiles = getMetaFiles(meta);
|
||||
|
||||
@ -62,8 +143,10 @@ public class ExportServlet extends HttpServlet {
|
||||
zo.closeEntry();
|
||||
}
|
||||
|
||||
zo.finish();
|
||||
zo.close();
|
||||
if (zo != null) {
|
||||
zo.finish();
|
||||
zo.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static List getMetaFiles(String blogHashes[]) {
|
||||
|
@ -2,34 +2,46 @@ package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetName;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.BlogURI;
|
||||
import net.i2p.syndie.sml.HTMLPreviewRenderer;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PostBean {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private User _user;
|
||||
private String _subject;
|
||||
private String _tags;
|
||||
private String _headers;
|
||||
private String _text;
|
||||
private String _archive;
|
||||
private List _filenames;
|
||||
private List _fileStreams;
|
||||
private List _localFiles;
|
||||
private List _fileTypes;
|
||||
private boolean _previewed;
|
||||
|
||||
public PostBean() { reinitialize(); }
|
||||
public PostBean() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(PostBean.class);
|
||||
reinitialize();
|
||||
}
|
||||
|
||||
public void reinitialize() {
|
||||
System.out.println("Reinitializing " + (_text != null ? "(with " + _text.length() + " bytes of sml!)" : ""));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Reinitializing " + (_text != null ? "(with " + _text.length() + " bytes of sml!)" : ""));
|
||||
_user = null;
|
||||
_subject = null;
|
||||
_tags = null;
|
||||
_text = null;
|
||||
_headers = null;
|
||||
_archive = null;
|
||||
_filenames = new ArrayList();
|
||||
_fileStreams = new ArrayList();
|
||||
_fileTypes = new ArrayList();
|
||||
@ -51,6 +63,7 @@ public class PostBean {
|
||||
public void setTags(String tags) { _tags = tags; }
|
||||
public void setText(String text) { _text = text; }
|
||||
public void setHeaders(String headers) { _headers = headers; }
|
||||
public void setArchive(String archive) { _archive = archive; }
|
||||
|
||||
public String getContentType(int id) {
|
||||
if ( (id >= 0) && (id < _fileTypes.size()) )
|
||||
@ -81,20 +94,45 @@ public class PostBean {
|
||||
File f = (File)_localFiles.get(i);
|
||||
localStreams.add(new FileInputStream(f));
|
||||
}
|
||||
return BlogManager.instance().createBlogEntry(_user, _subject, _tags, _headers, _text,
|
||||
_filenames, localStreams, _fileTypes);
|
||||
BlogURI uri = BlogManager.instance().createBlogEntry(_user, _subject, _tags, _headers, _text,
|
||||
_filenames, localStreams, _fileTypes);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Posted the entry " + uri.toString() + " (archive = " + _archive + ")");
|
||||
if ( (uri != null) && BlogManager.instance().authorizeRemote(_user) ) {
|
||||
PetName pn = _user.getPetNameDB().get(_archive);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Archive to petname? " + pn + " (protocol: " + (pn != null ? pn.getProtocol() : "") + ")");
|
||||
if ( (pn != null) && ("syndiearchive".equals(pn.getProtocol())) ) {
|
||||
RemoteArchiveBean r = new RemoteArchiveBean();
|
||||
Map params = new HashMap();
|
||||
params.put("localentry", new String[] { uri.toString() });
|
||||
String proxyHost = BlogManager.instance().getDefaultProxyHost();
|
||||
String port = BlogManager.instance().getDefaultProxyPort();
|
||||
int proxyPort = 4444;
|
||||
try { proxyPort = Integer.parseInt(port); } catch (NumberFormatException nfe) {}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Posting the entry " + uri.toString() + " to " + pn.getLocation());
|
||||
r.postSelectedEntries(_user, params, proxyHost, proxyPort, pn.getLocation());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Post status: " + r.getStatus());
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void renderPreview(Writer out) throws IOException {
|
||||
System.out.println("Subject: " + _subject);
|
||||
System.out.println("Text: " + _text);
|
||||
System.out.println("Headers: " + _headers);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Subject: " + _subject);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Text: " + _text);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Headers: " + _headers);
|
||||
// cache all the _fileStreams into temporary files, storing those files in _localFiles
|
||||
// then render the page accordingly with an HTMLRenderer, altered to use a different
|
||||
// 'view attachment'
|
||||
cacheAttachments();
|
||||
String smlContent = renderSMLContent();
|
||||
HTMLPreviewRenderer r = new HTMLPreviewRenderer(_filenames, _fileTypes, _localFiles);
|
||||
HTMLPreviewRenderer r = new HTMLPreviewRenderer(_context, _filenames, _fileTypes, _localFiles);
|
||||
r.render(_user, BlogManager.instance().getArchive(), null, smlContent, out, false, true);
|
||||
_previewed = true;
|
||||
}
|
||||
@ -128,7 +166,8 @@ public class PostBean {
|
||||
o.close();
|
||||
in.close();
|
||||
_localFiles.add(f);
|
||||
System.out.println("Caching attachment " + i + " temporarily in "
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Caching attachment " + i + " temporarily in "
|
||||
+ f.getAbsolutePath() + " w/ " + f.length() + "bytes");
|
||||
}
|
||||
_fileStreams.clear();
|
||||
|
95
apps/syndie/java/src/net/i2p/syndie/web/RSSServlet.java
Normal file
@ -0,0 +1,95 @@
|
||||
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.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RSSServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
req.setCharacterEncoding("UTF-8");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("application/rss+xml");
|
||||
|
||||
User user = (User)req.getSession().getAttribute("user");
|
||||
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.invalidate();
|
||||
}
|
||||
|
||||
String selector = req.getParameter("selector");
|
||||
if ( (selector == null) || (selector.length() <= 0) ) {
|
||||
selector = getDefaultSelector(user);
|
||||
}
|
||||
ArchiveViewerBean.Selector sel = new ArchiveViewerBean.Selector(selector);
|
||||
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
ArchiveIndex index = archive.getIndex();
|
||||
List entries = ArchiveViewerBean.pickEntryURIs(user, index, sel.blog, sel.tag, sel.entry, sel.group);
|
||||
|
||||
StringBuffer cur = new StringBuffer();
|
||||
cur.append(req.getScheme());
|
||||
cur.append("://");
|
||||
cur.append(req.getServerName());
|
||||
if (req.getServerPort() != 80)
|
||||
cur.append(':').append(req.getServerPort());
|
||||
cur.append(req.getContextPath()).append('/');
|
||||
String urlPrefix = cur.toString();
|
||||
|
||||
Writer out = resp.getWriter();
|
||||
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
|
||||
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");
|
||||
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);
|
||||
EntryContainer entry = archive.getEntry(uri);
|
||||
r.render(user, archive, entry, urlPrefix, out);
|
||||
}
|
||||
|
||||
out.write(" </channel>\n");
|
||||
out.write("</rss>\n");
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static String getDefaultSelector(User user) {
|
||||
if ( (user == null) || (user.getDefaultSelector() == null) )
|
||||
return BlogManager.instance().getArchive().getDefaultSelector();
|
||||
else
|
||||
return user.getDefaultSelector();
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.PetNameDB;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.EepGetScheduler;
|
||||
@ -12,11 +13,14 @@ import net.i2p.util.EepPost;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RemoteArchiveBean {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private String _remoteSchema;
|
||||
private String _remoteLocation;
|
||||
private String _proxyHost;
|
||||
@ -24,8 +28,11 @@ public class RemoteArchiveBean {
|
||||
private ArchiveIndex _remoteIndex;
|
||||
private List _statusMessages;
|
||||
private boolean _fetchIndexInProgress;
|
||||
private boolean _exportCapable;
|
||||
|
||||
public RemoteArchiveBean() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(RemoteArchiveBean.class);
|
||||
reinitialize();
|
||||
}
|
||||
public void reinitialize() {
|
||||
@ -35,6 +42,7 @@ public class RemoteArchiveBean {
|
||||
_fetchIndexInProgress = false;
|
||||
_proxyHost = null;
|
||||
_proxyPort = -1;
|
||||
_exportCapable = false;
|
||||
_statusMessages = new ArrayList();
|
||||
}
|
||||
|
||||
@ -51,6 +59,12 @@ public class RemoteArchiveBean {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private boolean ignoreBlog(User user, Hash blog) {
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
String name = db.getNameByLocation(blog.toBase64());
|
||||
return ( (name != null) && (db.get(name).isMember("Ignore")) );
|
||||
}
|
||||
|
||||
public void fetchMetadata(User user, Map parameters) {
|
||||
String meta = ArchiveViewerBean.getString(parameters, "blog");
|
||||
if (meta == null) return;
|
||||
@ -61,11 +75,17 @@ public class RemoteArchiveBean {
|
||||
for (Iterator iter = remoteBlogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (!localBlogs.contains(blog)) {
|
||||
blogs.add(blog);
|
||||
if (!ignoreBlog(user, blog))
|
||||
blogs.add(blog);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blogs.add(new Hash(Base64.decode(meta.trim())));
|
||||
byte h[] = Base64.decode(meta.trim());
|
||||
if (h != null) {
|
||||
Hash blog = new Hash(h);
|
||||
if (!ignoreBlog(user, blog))
|
||||
blogs.add(blog);
|
||||
}
|
||||
}
|
||||
List urls = new ArrayList(blogs.size());
|
||||
List tmpFiles = new ArrayList(blogs.size());
|
||||
@ -96,7 +116,10 @@ public class RemoteArchiveBean {
|
||||
List urls = new ArrayList(entries.length);
|
||||
List tmpFiles = new ArrayList(entries.length);
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
urls.add(buildEntryURL(new BlogURI(entries[i])));
|
||||
BlogURI uri = new BlogURI(entries[i]);
|
||||
if (ignoreBlog(user, uri.getKeyHash()))
|
||||
continue;
|
||||
urls.add(buildEntryURL(uri));
|
||||
try {
|
||||
tmpFiles.add(File.createTempFile("fetchBlog", ".txt", BlogManager.instance().getTempDir()));
|
||||
} catch (IOException ioe) {
|
||||
@ -118,6 +141,9 @@ public class RemoteArchiveBean {
|
||||
List matches = new ArrayList();
|
||||
for (Iterator iter = _remoteIndex.getUniqueBlogs().iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (ignoreBlog(user, blog))
|
||||
continue;
|
||||
|
||||
_remoteIndex.selectMatchesOrderByEntryId(matches, blog, null);
|
||||
for (int i = 0; i < matches.size(); i++) {
|
||||
BlogURI uri = (BlogURI)matches.get(i);
|
||||
@ -131,31 +157,58 @@ public class RemoteArchiveBean {
|
||||
entries[i] = ((BlogURI)uris.get(i)).toString();
|
||||
}
|
||||
if ( (entries == null) || (entries.length <= 0) ) return;
|
||||
StringBuffer url = new StringBuffer(512);
|
||||
url.append(buildExportURL());
|
||||
Set meta = new HashSet();
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
BlogURI uri = new BlogURI(entries[i]);
|
||||
if (uri.getEntryId() >= 0) {
|
||||
url.append("entry=").append(uri.toString()).append('&');
|
||||
meta.add(uri.getKeyHash());
|
||||
_statusMessages.add("Scheduling blog post fetching for " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
if (_exportCapable) {
|
||||
StringBuffer url = new StringBuffer(512);
|
||||
url.append(buildExportURL());
|
||||
StringBuffer postData = new StringBuffer(512);
|
||||
Set meta = new HashSet();
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
BlogURI uri = new BlogURI(entries[i]);
|
||||
if (uri.getEntryId() >= 0) {
|
||||
postData.append("entry=").append(uri.toString()).append('&');
|
||||
meta.add(uri.getKeyHash());
|
||||
_statusMessages.add("Scheduling bulk blog post fetch of " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
}
|
||||
}
|
||||
for (Iterator iter = meta.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
postData.append("meta=").append(blog.toBase64()).append('&');
|
||||
_statusMessages.add("Scheduling bulk blog metadata fetch of " + blog.toBase64());
|
||||
}
|
||||
try {
|
||||
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();
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + HTMLRenderer.sanitizeString(url.toString()) + ": " + ioe.getMessage());
|
||||
}
|
||||
} else {
|
||||
List urls = new ArrayList(entries.length+8);
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
BlogURI uri = new BlogURI(entries[i]);
|
||||
if (uri.getEntryId() >= 0) {
|
||||
String metaURL = buildMetaURL(uri.getKeyHash());
|
||||
if (!urls.contains(metaURL)) {
|
||||
urls.add(metaURL);
|
||||
_statusMessages.add("Scheduling blog metadata fetch of " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
}
|
||||
urls.add(buildEntryURL(uri));
|
||||
_statusMessages.add("Scheduling blog post fetch of " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
}
|
||||
}
|
||||
List tmpFiles = new ArrayList(1);
|
||||
try {
|
||||
for (int i = 0; i < urls.size(); i++) {
|
||||
File t = File.createTempFile("fetchBulk", ".dat", BlogManager.instance().getTempDir());
|
||||
tmpFiles.add(t);
|
||||
}
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener());
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch posts: " + HTMLRenderer.sanitizeString(urls.toString()));
|
||||
}
|
||||
}
|
||||
for (Iterator iter = meta.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
url.append("meta=").append(blog.toBase64()).append('&');
|
||||
_statusMessages.add("Scheduling blog metadata fetching for " + blog.toBase64());
|
||||
}
|
||||
List urls = new ArrayList(1);
|
||||
urls.add(url.toString());
|
||||
List tmpFiles = new ArrayList(1);
|
||||
try {
|
||||
File tmp = File.createTempFile("fetchBulk", ".zip", BlogManager.instance().getTempDir());
|
||||
tmpFiles.add(tmp);
|
||||
fetch(urls, tmpFiles, user, new BulkFetchListener(tmp));
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + HTMLRenderer.sanitizeString(url.toString()) + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,6 +230,8 @@ public class RemoteArchiveBean {
|
||||
List entries = new ArrayList();
|
||||
for (Iterator iter = _remoteIndex.getUniqueBlogs().iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (ignoreBlog(user, blog))
|
||||
continue;
|
||||
_remoteIndex.selectMatchesOrderByEntryId(entries, blog, null);
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
@ -213,9 +268,10 @@ public class RemoteArchiveBean {
|
||||
_remoteSchema = schema;
|
||||
_proxyHost = null;
|
||||
_proxyPort = -1;
|
||||
_exportCapable = false;
|
||||
|
||||
if ( (schema == null) || (schema.trim().length() <= 0) ||
|
||||
(location == null) || (location.trim().length() <= 0) ) {
|
||||
(location == null) || (location.trim().length() <= 0) ) {
|
||||
_statusMessages.add("Location must be specified");
|
||||
_fetchIndexInProgress = false;
|
||||
return;
|
||||
@ -240,13 +296,30 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
_statusMessages.add("Fetching index from " + HTMLRenderer.sanitizeString(_remoteLocation) +
|
||||
(_proxyHost != null ? " via " + HTMLRenderer.sanitizeString(_proxyHost) + ":" + _proxyPort : ""));
|
||||
(_proxyHost != null ? " via " + HTMLRenderer.sanitizeString(_proxyHost) + ":" + _proxyPort : ""));
|
||||
File archiveFile = new File(BlogManager.instance().getTempDir(), user.getBlog().toBase64() + "_remoteArchive.txt");
|
||||
archiveFile.delete();
|
||||
|
||||
Properties etags = new Properties();
|
||||
try {
|
||||
etags.load(new FileInputStream(new File(BlogManager.instance().getRootDir(), "etags")));
|
||||
} catch (Exception exp) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
EepGet eep = new EepGet(I2PAppContext.getGlobalContext(), ((_proxyHost != null) && (_proxyPort > 0)),
|
||||
_proxyHost, _proxyPort, 0, archiveFile.getAbsolutePath(), location);
|
||||
_proxyHost, _proxyPort, 0, archiveFile.getAbsolutePath(), location, etags.getProperty(location));
|
||||
eep.addStatusListener(new IndexFetcherStatusListener(archiveFile));
|
||||
eep.fetch();
|
||||
|
||||
if (eep.getETag() != null) {
|
||||
etags.setProperty(location, eep.getETag());
|
||||
}
|
||||
try {
|
||||
etags.store(new FileOutputStream(new File(BlogManager.instance().getRootDir(), "etags")), "etags");
|
||||
} catch (Exception exp) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
private class IndexFetcherStatusListener implements EepGet.StatusListener {
|
||||
@ -259,22 +332,33 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " successful");
|
||||
_fetchIndexInProgress = false;
|
||||
ArchiveIndex i = new ArchiveIndex(false);
|
||||
try {
|
||||
i.load(_archiveFile);
|
||||
_statusMessages.add("Archive fetched and loaded");
|
||||
_remoteIndex = i;
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Archive is corrupt: " + ioe.getMessage());
|
||||
ArchiveIndex i = new ArchiveIndex(I2PAppContext.getGlobalContext(), false);
|
||||
if (!notModified) {
|
||||
try {
|
||||
i.load(_archiveFile);
|
||||
_statusMessages.add("Archive fetched and loaded");
|
||||
_remoteIndex = i;
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Archive is corrupt: " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " failed after " + bytesTransferred);
|
||||
_fetchIndexInProgress = false;
|
||||
}
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val) {
|
||||
if (ArchiveServlet.HEADER_EXPORT_CAPABLE.equals(key) && ("true".equals(val))) {
|
||||
_statusMessages.add("Remote archive is bulk export capable");
|
||||
_exportCapable = true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Header received: [" + key + "] = [" + val + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MetadataStatusListener implements EepGet.StatusListener {
|
||||
@ -284,31 +368,37 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " successful");
|
||||
File info = new File(outputFile);
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
BlogInfo i = new BlogInfo();
|
||||
in = new FileInputStream(info);
|
||||
i.load(in);
|
||||
boolean ok = BlogManager.instance().getArchive().storeBlogInfo(i);
|
||||
if (ok) {
|
||||
_statusMessages.add("Blog info for " + HTMLRenderer.sanitizeString(i.getProperty(BlogInfo.NAME)) + " imported");
|
||||
BlogManager.instance().getArchive().reloadInfo();
|
||||
} else {
|
||||
_statusMessages.add("Blog info at " + HTMLRenderer.sanitizeString(url) + " was corrupt / invalid / forged");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
info.delete();
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
handleMetadata(url, outputFile);
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " failed after " + bytesTransferred);;
|
||||
}
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
||||
}
|
||||
|
||||
private void handleMetadata(String url, String outputFile) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " successful");
|
||||
File info = new File(outputFile);
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
BlogInfo i = new BlogInfo();
|
||||
in = new FileInputStream(info);
|
||||
i.load(in);
|
||||
boolean ok = BlogManager.instance().getArchive().storeBlogInfo(i);
|
||||
if (ok) {
|
||||
_statusMessages.add("Blog info for " + HTMLRenderer.sanitizeString(i.getProperty(BlogInfo.NAME)) + " imported");
|
||||
BlogManager.instance().getArchive().reloadInfo();
|
||||
} else {
|
||||
_statusMessages.add("Blog info at " + HTMLRenderer.sanitizeString(url) + " was corrupt / invalid / forged");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error handling metadata", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
info.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private class BlogStatusListener implements EepGet.StatusListener {
|
||||
@ -318,7 +408,11 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
if (url.endsWith(".snm")) {
|
||||
handleMetadata(url, outputFile);
|
||||
return;
|
||||
}
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " successful");
|
||||
File file = new File(outputFile);
|
||||
FileInputStream in = null;
|
||||
@ -346,7 +440,8 @@ public class RemoteArchiveBean {
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error importing", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
file.delete();
|
||||
@ -355,6 +450,7 @@ public class RemoteArchiveBean {
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " failed after " + bytesTransferred);
|
||||
}
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -371,7 +467,7 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url.substring(0, url.indexOf('?'))) + " successful, importing the data");
|
||||
File file = new File(outputFile);
|
||||
ZipInputStream zi = null;
|
||||
@ -424,7 +520,8 @@ public class RemoteArchiveBean {
|
||||
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.debug("Error importing", ioe);
|
||||
_statusMessages.add("Error importing from " + HTMLRenderer.sanitizeString(url) + ": " + ioe.getMessage());
|
||||
} finally {
|
||||
if (zi != null) try { zi.close(); } catch (IOException ioe) {}
|
||||
@ -435,15 +532,26 @@ public class RemoteArchiveBean {
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " failed after " + bytesTransferred);
|
||||
_tmp.delete();
|
||||
}
|
||||
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
||||
}
|
||||
|
||||
public void postSelectedEntries(User user, Map parameters) {
|
||||
postSelectedEntries(user, parameters, _proxyHost, _proxyPort, _remoteLocation);
|
||||
}
|
||||
public void postSelectedEntries(User user, Map parameters, String proxyHost, int proxyPort, String location) {
|
||||
String entries[] = ArchiveViewerBean.getStrings(parameters, "localentry");
|
||||
if ( (entries == null) || (entries.length <= 0) ) return;
|
||||
List uris = new ArrayList(entries.length);
|
||||
for (int i = 0; i < entries.length; i++)
|
||||
uris.add(new BlogURI(entries[i]));
|
||||
|
||||
if ( (proxyPort > 0) && (proxyHost != null) && (proxyHost.trim().length() > 0) ) {
|
||||
_proxyPort = proxyPort;
|
||||
_proxyHost = proxyHost;
|
||||
} else {
|
||||
_proxyPort = -1;
|
||||
_proxyHost = null;
|
||||
}
|
||||
_remoteLocation = location;
|
||||
post(uris, user);
|
||||
}
|
||||
|
||||
@ -480,12 +588,14 @@ public class RemoteArchiveBean {
|
||||
public void renderDeltaForm(User user, ArchiveIndex localIndex, Writer out) throws IOException {
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
buf.append("<b>New blogs:</b> <select name=\"blog\"><option value=\"ALL\">All</option>\n");
|
||||
buf.append("<em class=\"b_remMeta\">New blogs:</em> <select class=\"b_remMeta\"name=\"blog\"><option value=\"ALL\">All</option>\n");
|
||||
Set localBlogs = archive.getIndex().getUniqueBlogs();
|
||||
Set remoteBlogs = _remoteIndex.getUniqueBlogs();
|
||||
int newBlogs = 0;
|
||||
for (Iterator iter = remoteBlogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (ignoreBlog(user, blog))
|
||||
continue;
|
||||
if (!localBlogs.contains(blog)) {
|
||||
buf.append("<option value=\"" + blog.toBase64() + "\">" + blog.toBase64() + "</option>\n");
|
||||
newBlogs++;
|
||||
@ -493,48 +603,57 @@ public class RemoteArchiveBean {
|
||||
}
|
||||
if (newBlogs > 0) {
|
||||
out.write(buf.toString());
|
||||
out.write("</select> <input type=\"submit\" name=\"action\" value=\"Fetch metadata\" /><br />\n");
|
||||
out.write("</select> <input class=\"b_remMetaFetch\" type=\"submit\" name=\"action\" value=\"Fetch metadata\" /><br />\n");
|
||||
}
|
||||
|
||||
int newEntries = 0;
|
||||
int localNew = 0;
|
||||
out.write("<table border=\"1\" width=\"100%\">\n");
|
||||
out.write("<table class=\"b_remDelta\" border=\"1\" width=\"100%\">\n");
|
||||
List entries = new ArrayList();
|
||||
for (Iterator iter = remoteBlogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (ignoreBlog(user, blog))
|
||||
continue;
|
||||
buf.setLength(0);
|
||||
int shownEntries = 0;
|
||||
buf.append("<tr><td colspan=\"5\" align=\"left\" valign=\"top\">\n");
|
||||
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 href=\"" + HTMLRenderer.getPageURL(blog, null, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\"><b>" + HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME)) + "</b></a>: " +
|
||||
HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.DESCRIPTION)) + "\n");
|
||||
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("<span class=\"b_remBlogDesc\">").append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.DESCRIPTION)));
|
||||
buf.append("</span>\n");
|
||||
} else {
|
||||
buf.append("<b>" + blog.toBase64() + "</b>\n");
|
||||
buf.append("<span class=\"b_remBlog\">" + blog.toBase64() + "</span>\n");
|
||||
}
|
||||
buf.append("</td></tr>\n");
|
||||
buf.append("<tr><td> </td><td nowrap=\"true\"><b>Posted on</b></td><td nowrap=\"true\"><b>#</b></td><td nowrap=\"true\"><b>Size</b></td><td width=\"90%\" nowrap=\"true\"><b>Tags</b></td></tr>\n");
|
||||
buf.append("<tr class=\"b_remHeader\"><td class=\"b_remHeader\"> </td><td class=\"b_remHeader\" nowrap=\"nowrap\">");
|
||||
buf.append("<em class=\"b_remHeader\">Posted on</em></td>");
|
||||
buf.append("<td class=\"b_remHeader\" nowrap=\"nowrap\"><em class=\"b_remHeader\">#</em></td>");
|
||||
buf.append("<td class=\"b_remHeader\" nowrap=\"nowrap\"><em class=\"b_remHeader\">Size</em></td>");
|
||||
buf.append("<td class=\"b_remHeader\" width=\"90%\" nowrap=\"true\"><em class=\"b_remHeader\">Tags</em></td></tr>\n");
|
||||
entries.clear();
|
||||
_remoteIndex.selectMatchesOrderByEntryId(entries, blog, null);
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
buf.append("<tr>\n");
|
||||
buf.append("<tr class=\"b_remDetail\">\n");
|
||||
if (!archive.getIndex().getEntryIsKnown(uri)) {
|
||||
buf.append("<td><input type=\"checkbox\" name=\"entry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
buf.append("<td class=\"b_remDetail\"><input class=\"b_remSelect\" type=\"checkbox\" name=\"entry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
newEntries++;
|
||||
shownEntries++;
|
||||
} else {
|
||||
String page = HTMLRenderer.getPageURL(blog, null, uri.getEntryId(), -1, -1,
|
||||
user.getShowExpanded(), user.getShowImages());
|
||||
buf.append("<td><a href=\"" + page + "\">(local)</a></td>\n");
|
||||
buf.append("<td class=\"b_remDetail\"><a class=\"b_remLocal\" href=\"" + page + "\">(local)</a></td>\n");
|
||||
}
|
||||
buf.append("<td>" + getDate(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + getId(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + _remoteIndex.getBlogEntrySizeKB(uri) + "KB</td>\n");
|
||||
buf.append("<td>");
|
||||
buf.append("<td class=\"b_remDetail\"><span class=\"b_remDate\">" + getDate(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remDetail\"><span class=\"b_remNum\">" + getId(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remDetail\"><span class=\"b_remSize\">" + _remoteIndex.getBlogEntrySizeKB(uri) + "KB</span></td>\n");
|
||||
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 href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
buf.append("<a class=\"b_remTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
@ -548,22 +667,22 @@ public class RemoteArchiveBean {
|
||||
// now for posts in known blogs that we have and they don't
|
||||
entries.clear();
|
||||
localIndex.selectMatchesOrderByEntryId(entries, blog, null);
|
||||
buf.append("<tr><td colspan=\"5\">Entries we have, but the remote Syndie doesn't:</td></tr>\n");
|
||||
buf.append("<tr class=\"b_remLocalHeader\"><td class=\"b_remLocalHeader\" colspan=\"5\"><span class=\"b_remLocalHeader\">Entries we have, but the remote Syndie doesn't:</span></td></tr>\n");
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
if (!_remoteIndex.getEntryIsKnown(uri)) {
|
||||
buf.append("<tr>\n");
|
||||
buf.append("<td><input type=\"checkbox\" name=\"localentry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
buf.append("<tr class=\"b_remLocalDetail\">\n");
|
||||
buf.append("<td class=\"b_remLocalDetail\"><input class=\"b_remLocalSend\" type=\"checkbox\" name=\"localentry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
shownEntries++;
|
||||
newEntries++;
|
||||
localNew++;
|
||||
buf.append("<td>" + getDate(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + getId(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + localIndex.getBlogEntrySizeKB(uri) + "KB</td>\n");
|
||||
buf.append("<td>");
|
||||
buf.append("<td class=\"b_remLocalDate\"><span class=\"b_remLocalDate\">" + getDate(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remLocalNum\"><span class=\"b_remLocalNum\">" + getId(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remLocalSize\"><span class=\"b_remLocalSize\">" + localIndex.getBlogEntrySizeKB(uri) + "KB</span></td>\n");
|
||||
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 href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
@ -577,12 +696,14 @@ public class RemoteArchiveBean {
|
||||
// now for posts in blogs we have and they don't
|
||||
int newBefore = localNew;
|
||||
buf.setLength(0);
|
||||
buf.append("<tr><td colspan=\"5\">Blogs the remote Syndie doesn't have</td></tr>\n");
|
||||
buf.append("<tr class=\"b_remLocalHeader\"><td class=\"b_remLocalHeader\" colspan=\"5\"><span class=\"b_remLocalHeader\">Blogs the remote Syndie doesn't have</span></td></tr>\n");
|
||||
for (Iterator iter = localBlogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (remoteBlogs.contains(blog)) {
|
||||
//System.err.println("Remote index has " + blog.toBase64());
|
||||
continue;
|
||||
} else if (ignoreBlog(user, blog)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.clear();
|
||||
@ -590,15 +711,15 @@ public class RemoteArchiveBean {
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
buf.append("<tr>\n");
|
||||
buf.append("<td><input type=\"checkbox\" name=\"localentry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
buf.append("<td>" + getDate(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + getId(uri.getEntryId()) + "</td>\n");
|
||||
buf.append("<td>" + localIndex.getBlogEntrySizeKB(uri) + "KB</td>\n");
|
||||
buf.append("<td>");
|
||||
buf.append("<tr class=\"b_remLocalDetail\">\n");
|
||||
buf.append("<td class=\"b_remLocalDetail\"><input class=\"b_remLocalSend\" type=\"checkbox\" name=\"localentry\" value=\"" + uri.toString() + "\" /></td>\n");
|
||||
buf.append("<td class=\"b_remLocalDate\"><span class=\"b_remLocalDate\">" + getDate(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remLocalNum\"><span class=\"b_remLocalNum\">" + getId(uri.getEntryId()) + "</span></td>\n");
|
||||
buf.append("<td class=\"b_remLocalSize\"><span class=\"b_remLocalSize\">" + localIndex.getBlogEntrySizeKB(uri) + "KB</span></td>\n");
|
||||
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 href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
buf.append("<a class=\"b_remLocalTag\" href=\"" + HTMLRenderer.getPageURL(blog, tag, -1, -1, -1, user.getShowExpanded(), user.getShowImages()) + "\">" + tag + "</a> \n");
|
||||
}
|
||||
buf.append("</td>\n");
|
||||
buf.append("</tr>\n");
|
||||
@ -610,13 +731,13 @@ public class RemoteArchiveBean {
|
||||
|
||||
out.write("</table>\n");
|
||||
if (newEntries > 0) {
|
||||
out.write("<input type=\"submit\" name=\"action\" value=\"Fetch selected entries\" /> \n");
|
||||
out.write("<input type=\"submit\" name=\"action\" value=\"Fetch all new entries\" /> \n");
|
||||
out.write("<input class=\"b_remFetchSelected\" type=\"submit\" name=\"action\" value=\"Fetch selected entries\" /> \n");
|
||||
out.write("<input class=\"b_remFetchAll\" type=\"submit\" name=\"action\" value=\"Fetch all new entries\" /> \n");
|
||||
} else {
|
||||
out.write(HTMLRenderer.sanitizeString(_remoteLocation) + " has no new posts to offer us\n");
|
||||
out.write("<span class=\"b_remNoRemotePosts\">" + HTMLRenderer.sanitizeString(_remoteLocation) + " has no new posts to offer us</span>\n");
|
||||
}
|
||||
if (localNew > 0) {
|
||||
out.write("<input type=\"submit\" name=\"action\" value=\"Post selected entries\" /> \n");
|
||||
out.write("<input class=\"b_remPostSelected\" type=\"submit\" name=\"action\" value=\"Post selected entries\" /> \n");
|
||||
}
|
||||
out.write("<hr />\n");
|
||||
}
|
||||
|
@ -1,9 +1,39 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" import="net.i2p.syndie.web.ArchiveViewerBean, net.i2p.syndie.*" %>
|
||||
<%@page contentType="text/html; charset=UTF-8" import="net.i2p.syndie.web.ArchiveViewerBean, net.i2p.syndie.*, net.i2p.client.naming.PetName" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" /><table border="0" width="100%">
|
||||
<tr><form action="index.jsp"><td nowrap="true">
|
||||
<b>Blogs:</b> <%ArchiveViewerBean.renderBlogSelector(user, request.getParameterMap(), out);%>
|
||||
<input type="submit" value="Refresh" />
|
||||
<input type="submit" name="action" value="<%=ArchiveViewerBean.SEL_ACTION_SET_AS_DEFAULT%>" />
|
||||
<!-- char encoding: [<%=response.getCharacterEncoding()%>] content type [<%=response.getContentType()%>] Locale [<%=response.getLocale()%>] -->
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" /><%
|
||||
if (user.getAuthenticated() && (null != request.getParameter("action")) ) {
|
||||
%><!-- <%=request.getParameterMap()%> --><%
|
||||
String blog = request.getParameter("blog");
|
||||
String group = null;
|
||||
if (request.getParameter("action").equals("Bookmark blog"))
|
||||
group = "Favorites";
|
||||
else if (request.getParameter("action").equals("Ignore blog"))
|
||||
group = "Ignore";
|
||||
boolean unignore = ("Unignore blog".equals(request.getParameter("action")));
|
||||
|
||||
String name = user.getPetNameDB().getNameByLocation(blog);
|
||||
if (name == null)
|
||||
name = request.getParameter("name");
|
||||
if (name == null)
|
||||
name = blog;
|
||||
if ( (name != null) && (blog != null) && ( (group != null) || (unignore) ) ) {
|
||||
PetName pn = user.getPetNameDB().get(name);
|
||||
if (pn != null) {
|
||||
if (unignore)
|
||||
pn.removeGroup("Ignore");
|
||||
else
|
||||
pn.addGroup(group);
|
||||
} else {
|
||||
pn = new PetName(name, "syndie", "syndieblog", blog);
|
||||
pn.addGroup(group);
|
||||
user.getPetNameDB().set(name, pn);
|
||||
}
|
||||
BlogManager.instance().saveUser(user);
|
||||
}
|
||||
}
|
||||
%><table border="0" width="100%" class="b_content">
|
||||
<tr class="b_content"><form action="index.jsp"><td nowrap="nowrap">
|
||||
<em class="b_selectorTitle">Blogs:</em> <span class="b_selector"><%ArchiveViewerBean.renderBlogSelector(user, request.getParameterMap(), out);%></span>
|
||||
<input type="submit" value="Refresh" class="b_selectorRefresh" />
|
||||
<input type="submit" name="action" value="<%=ArchiveViewerBean.SEL_ACTION_SET_AS_DEFAULT%>" class="b_selectorDefault" />
|
||||
<%ArchiveViewerBean.renderBlogs(user, request.getParameterMap(), out, "</td></form></tr><tr><td align=\"left\" valign=\"top\">");%></td></tr></table>
|
@ -1,14 +1,18 @@
|
||||
<%@page import="net.i2p.syndie.*, net.i2p.syndie.sml.*, net.i2p.syndie.web.*" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<td valign="top" align="left" class="syndieTopNavBlogsCell" height="10"><a href="index.jsp">Home</a></td>
|
||||
<td valign="top" align="left" class="syndieTopNavRemoteCell" height="10">
|
||||
<a href="remote.jsp">Remote archives</a>
|
||||
<a href="import.jsp">Import</a>
|
||||
</td>
|
||||
<form action="<%=request.getRequestURI() + "?" + (request.getQueryString() != null ? request.getQueryString() : "")%>">
|
||||
<td nowrap="true" valign="top" align="right" class="syndieTopNavManageCell" height="10"><%
|
||||
<td nowrap="nowrap" colspan="2" height="10" class="b_topnav">
|
||||
<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="import.jsp" class="b_topnavImport">Import</a>
|
||||
</td><td nowrap="nowrap" height="10" class="b_topnavUser"><%
|
||||
if ("true".equals(request.getParameter("logout"))) {
|
||||
user.invalidate();
|
||||
RemoteArchiveBean rem = (RemoteArchiveBean)session.getAttribute("remote");
|
||||
if (rem != null) rem.reinitialize();
|
||||
PostBean post = (PostBean)session.getAttribute("post");
|
||||
if (post != null) post.reinitialize();
|
||||
}
|
||||
String login = request.getParameter("login");
|
||||
String pass = request.getParameter("password");
|
||||
@ -16,27 +20,27 @@ String loginSubmit = request.getParameter("Login");
|
||||
if ( (login != null) && (pass != null) && (loginSubmit != null) && (loginSubmit.equals("Login")) ) {
|
||||
String loginResult = BlogManager.instance().login(user, login, pass);
|
||||
if (!user.getAuthenticated())
|
||||
out.write("<b>" + loginResult + "</b>");
|
||||
out.write("<b class=\"b_topnavLoginResult\">" + loginResult + "</b>");
|
||||
}
|
||||
%>
|
||||
<% if (user.getAuthenticated()) { %>
|
||||
Logged in as: <b><jsp:getProperty property="username" name="user" />:</b>
|
||||
<a href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())%>"><%=HTMLRenderer.sanitizeString(ArchiveViewerBean.getBlogName(user.getBlogStr()))%></a>
|
||||
<a href="<%=HTMLRenderer.getPostURL(user.getBlog())%>">Post</a>
|
||||
<a href="<%=HTMLRenderer.getMetadataURL(user.getBlog())%>">Metadata</a>
|
||||
<a href="index.jsp?logout=true">Logout</a><br />
|
||||
<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_topnavAddr" href="addresses.jsp">Addressbook</a>
|
||||
<a class="b_topnavLogout" href="index.jsp?logout=true">Logout</a>
|
||||
<%} else {%>
|
||||
Login: <input type="text" name="login" size="8" />
|
||||
Pass: <input type="password" name="password" size="8" /><%
|
||||
<span class="b_topnavLogin">Login:</span> <input class="b_topnavLogin" type="text" name="login" size="8" />
|
||||
<span class="b_topnavPass">Pass:</span> <input class="b_topnavPass" type="password" name="password" size="8" /><%
|
||||
java.util.Enumeration params = request.getParameterNames();
|
||||
while (params.hasMoreElements()) {
|
||||
String p = (String)params.nextElement();
|
||||
String val = request.getParameter(p);
|
||||
%><input type="hidden" name="<%=p%>" value="<%=val%>" /><%
|
||||
}%>
|
||||
<input type="submit" name="Login" value="Login" />
|
||||
<a href="register.jsp">Register</a>
|
||||
<input class="b_topnavLoginSubmit" type="submit" name="Login" value="Login" />
|
||||
<a class="b_topnavRegister" href="register.jsp">Register</a>
|
||||
<% } %>
|
||||
|
||||
</td>
|
||||
</form>
|
@ -1,47 +0,0 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.*, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.*" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<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><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3"><%
|
||||
String nameStr = request.getParameter("name");
|
||||
String locStr = request.getParameter("location");
|
||||
String schemaStr = request.getParameter("schema");
|
||||
String name = null;
|
||||
String location = null;
|
||||
String schema = null;
|
||||
try {
|
||||
name = DataHelper.getUTF8(Base64.decode(nameStr));
|
||||
location = DataHelper.getUTF8(Base64.decode(locStr));
|
||||
schema = DataHelper.getUTF8(Base64.decode(schemaStr));
|
||||
} catch (NullPointerException npe) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if ( (name == null) || (location == null) || (schema == null) ) {
|
||||
out.write("<b>No location specified</b>");
|
||||
} else if (user.getAuthenticated() && ("Add".equals(request.getParameter("action"))) ) {
|
||||
out.write("<b>" + BlogManager.instance().addAddress(user, name, location, schema) + "</b>");
|
||||
} else { %>Are you sure you really want to add the
|
||||
addressbook mapping of <%=HTMLRenderer.sanitizeString(name)%> to
|
||||
<input type="text" size="20" value="<%=HTMLRenderer.sanitizeString(location)%>" />, applicable within the
|
||||
schema <%=HTMLRenderer.sanitizeString(schema)%>?
|
||||
<% if (!user.getAuthenticated()) { %>
|
||||
<p />If so, add the line
|
||||
<input type="text" size="20" value="<%=HTMLRenderer.sanitizeString(name)%>=<%=HTMLRenderer.sanitizeString(location)%>" />
|
||||
to your <code>userhosts.txt</code>.
|
||||
<% } else { %><br />
|
||||
<a href="addaddress.jsp?name=<%=HTMLRenderer.sanitizeURL(name)%>&location=<%=HTMLRenderer.sanitizeURL(location)%>&schema=<%=HTMLRenderer.sanitizeURL(schema)%>&action=Add">Yes, add it</a>.
|
||||
<% }
|
||||
} %></td></tr>
|
||||
</table>
|
||||
</body>
|
202
apps/syndie/jsp/addresses.jsp
Normal file
@ -0,0 +1,202 @@
|
||||
<%@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>
|
||||
<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.get(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.remove(oldPetname);
|
||||
names.set(cur.getName(), cur);
|
||||
names.store(user.getAddressbookLocation());
|
||||
%><span class="b_addrMsgOk">Address updated</span><%
|
||||
}
|
||||
} else if ( (action != null) && ("Add".equals(action)) ) {
|
||||
PetName cur = names.get(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.set(cur.getName(), cur);
|
||||
names.store(user.getAddressbookLocation());
|
||||
%><span class="b_addrMsgOk">Address added</span><%
|
||||
}
|
||||
} else if ( (action != null) && ("Delete".equals(action)) ) {
|
||||
PetName cur = names.get(request.getParameter("name"));
|
||||
if (cur != null) {
|
||||
names.remove(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">Groups</em></td>
|
||||
<td class="b_addrHeader"> </td></tr>
|
||||
<%
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
for (Iterator iter = sorted.iterator(); iter.hasNext(); ) {
|
||||
PetName name = names.get((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_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_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>
|
93
apps/syndie/jsp/admin.jsp
Normal file
@ -0,0 +1,93 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.data.*, net.i2p.syndie.*, org.mortbay.servlet.MultiPartRequest, java.util.*, java.io.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd"><html>
|
||||
<head>
|
||||
<title>SyndieMedia admin</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
if (!user.getAuthenticated()) {
|
||||
%><span class="b_adminMsgErr">You must be logged in to configure your Syndie instance!</span><%
|
||||
} else {
|
||||
String action = request.getParameter("action");
|
||||
if ( (action != null) && ("Save".equals(action)) ) {
|
||||
boolean configured = BlogManager.instance().isConfigured();
|
||||
String adminPass = request.getParameter("adminpass");
|
||||
String regPass = request.getParameter("regpass");
|
||||
String remotePass = request.getParameter("remotepass");
|
||||
String proxyHost = request.getParameter("proxyhost");
|
||||
String proxyPort = request.getParameter("proxyport");
|
||||
String selector = request.getParameter("selector");
|
||||
boolean isSingleUser = BlogManager.instance().isSingleUser();
|
||||
String singleSet = request.getParameter("singleuser");
|
||||
if (singleSet != null)
|
||||
isSingleUser = true;
|
||||
else
|
||||
isSingleUser = false;
|
||||
|
||||
if (configured) {
|
||||
if (BlogManager.instance().authorizeAdmin(adminPass)) {
|
||||
int port = -1;
|
||||
try { port = Integer.parseInt(proxyPort); } catch (NumberFormatException nfe) { port = 4444; }
|
||||
BlogManager.instance().configure(regPass, remotePass, adminPass, selector, proxyHost, port, isSingleUser, null);
|
||||
%><span class="b_adminMsgOk">Configuration updated</span><%
|
||||
} else {
|
||||
%><span class="b_adminMsgErr">Invalid admin password. If you lost it, please update your syndie.config.</span><%
|
||||
}
|
||||
} else {
|
||||
int port = -1;
|
||||
try { port = Integer.parseInt(proxyPort); } catch (NumberFormatException nfe) { port = 4444; }
|
||||
BlogManager.instance().configure(regPass, remotePass, adminPass, selector, proxyHost, port, isSingleUser, null);
|
||||
%><span class="b_adminMsgOk">Configuration saved</span><%
|
||||
}
|
||||
} else {
|
||||
%><form action="admin.jsp" method="POST">
|
||||
<em class="b_adminField">Single user?</em> <input type="checkbox" class="b_adminField" name="singleuser" <%=BlogManager.instance().isSingleUser() ? " checked=\"true\" " : ""%> /><br />
|
||||
<span class="b_adminDescr">If this is checked, the registration, admin, and remote passwords are unnecessary - anyone
|
||||
can register and administer Syndie, as well as use any remote functionality. This should not be checked if untrusted
|
||||
parties can access this web interface.</span><br />
|
||||
<em class="b_adminField">Registration password:</em> <input class="b_adminField" type="text" name="regpass" size="10" /><br />
|
||||
<span class="b_adminDescr">Users must specify this password on the registration form to proceed. If this is
|
||||
blank, anyone can register.</span><br />
|
||||
<em class="b_adminField">Remote password:</em> <input class="b_adminField" type="text" name="remotepass" size="10" /><br />
|
||||
<span class="b_adminDescr">To access remote archives, users must first provide this password on their
|
||||
metadata page. Remote access is 'dangerous', as it allows the user to instruct
|
||||
this Syndie instance to establish HTTP connections with arbitrary locations. If
|
||||
this field is not specified, no one can use remote archives.</span><br />
|
||||
<em class="b_adminField">Default remote proxy host:</em> <input class="b_adminField" type="text" name="proxyhost" size="20" value="localhost" /><br />
|
||||
<em class="b_adminField">Default remote proxy port:</em> <input class="b_adminField" type="text" name="proxyport" size="5" value="4444" /><br />
|
||||
<span class="b_adminDescr">This is the default HTTP proxy shown on the remote archive page.</span><br />
|
||||
<em class="b_adminField">Default blog selector:</em> <input class="b_adminField" type="text" name="selector" size="40" value="ALL" /><br />
|
||||
<span class="b_adminDescr">The selector lets you choose what blog (or blogs) are shown on the front page for
|
||||
new, unregistered users. Valid values include:<ul class="b_adminDescr">
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">ALL</code>: all blogs</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">blog://$blogHash</code>: all posts in the blog identified by $blogHash</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">blogtag://$blogHash/$tagBase64</code>: all posts in the blog identified by $blogHash
|
||||
tagged by the tag whose modified base64 encoding is $tagBase64</li>
|
||||
<li class="b_adminDescr"><code class="b_adminDescr">tag://$tagBase64</code>: all posts in any blog tagged by the tag whose
|
||||
modified base64 encoding is $tagBase64</li>
|
||||
</ul>
|
||||
</span>
|
||||
<hr />
|
||||
<% if (!BlogManager.instance().isConfigured()) {
|
||||
long passNum = new Random().nextLong(); %>
|
||||
<em class="b_adminField">Administrative password:</em> <input class="b_adminField" type="password" name="adminpass" size="10" value="<%=passNum%>" /> <br />
|
||||
<span class="b_adminDescr b_adminDescrFirstRun">Since this Syndie instance is not already configured, you can specify a new
|
||||
administrative password which must be presented whenever you update this configuration.
|
||||
The default value filled in there is <code class="b_adminDescr b_adminDescrFirstRun"><%=passNum%></code></span><br />
|
||||
<% } else { %>
|
||||
<em class="b_adminField">Administrative password:</em> <input class="b_adminField" type="password" name="adminpass" size="10" value="" /> <br />
|
||||
<% } %>
|
||||
<input class="b_adminSave" type="submit" name="action" value="Save" />
|
||||
<% }
|
||||
} %>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
@ -1,17 +1,19 @@
|
||||
<%@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"); %>
|
||||
<%@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" />
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3">Are you sure you really want to go to
|
||||
<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");
|
||||
@ -21,14 +23,14 @@ if (schema != null) schema = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base
|
||||
if (desc != null) desc = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(desc)));
|
||||
|
||||
if ( (loc != null) && (schema != null) ) {
|
||||
out.write(loc + " (" + schema + ")");
|
||||
out.write("<span class=\"b_externalLoc\">" + loc + "</span> <span class=\"b_externalNet\"(" + schema + ")</span>");
|
||||
if (desc != null)
|
||||
out.write(": " + desc);
|
||||
out.write(": <span class=\"b_externalDesc\"" + desc + "\"</span>");
|
||||
out.write("? ");
|
||||
out.write("<a href=\"" + loc + "\">yes</a>");
|
||||
out.write("<a class=\"b_external\" href=\"" + loc + "\">yes</a>");
|
||||
} else {
|
||||
out.write("(some unspecified location...)");
|
||||
out.write("<span class=\"b_externalUnknown\">(some unspecified location...)</span>");
|
||||
}
|
||||
%></td></tr>
|
||||
%></span></td></tr>
|
||||
</table>
|
||||
</body>
|
@ -1,18 +1,19 @@
|
||||
<%@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.data.TransparentArchiveIndex" id="archive" />
|
||||
<%@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.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 import</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" />
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3"><%
|
||||
<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"><%
|
||||
|
||||
String contentType = request.getContentType();
|
||||
if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
@ -20,10 +21,10 @@ if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
int metaId = 0;
|
||||
while (true) {
|
||||
InputStream meta = req.getInputStream("blogmeta" + metaId);
|
||||
if (meta == null)
|
||||
if ( (meta == null) || (meta.available() <= 0) )
|
||||
break;
|
||||
if (!BlogManager.instance().importBlogMetadata(meta)) {
|
||||
System.err.println("blog meta " + metaId + " failed to be imported");
|
||||
%><span class="b_importMsgErr">Metadata <%=metaId%> failed to be imported</span><br /><%
|
||||
break;
|
||||
}
|
||||
metaId++;
|
||||
@ -31,10 +32,10 @@ if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
int entryId = 0;
|
||||
while (true) {
|
||||
InputStream entry = req.getInputStream("blogpost" + entryId);
|
||||
if (entry == null)
|
||||
if ( (entry == null) || (entry.available() <= 0) )
|
||||
break;
|
||||
if (!BlogManager.instance().importBlogEntry(entry)) {
|
||||
System.err.println("blog entry " + entryId + " failed to be imported");
|
||||
%><span class="b_importMsgErr">Entry <%=entryId%> failed to be imported</span><br /><%
|
||||
break;
|
||||
}
|
||||
entryId++;
|
||||
@ -44,23 +45,23 @@ if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
session.setAttribute("index", BlogManager.instance().getArchive().getIndex());
|
||||
}
|
||||
%>Imported <%=entryId%> posts and <%=metaId%> blog metadata files.
|
||||
%><span class="b_importMsgOk">Imported <%=entryId%> posts and <%=metaId%> blog metadata files.</span>
|
||||
<%
|
||||
} else { %><form action="import.jsp" method="POST" enctype="multipart/form-data">
|
||||
Blog metadata 0: <input type="file" name="blogmeta0" /><br />
|
||||
Blog metadata 1: <input type="file" name="blogmeta1" /><br />
|
||||
Post 0: <input type="file" name="blogpost0" /><br />
|
||||
Post 1: <input type="file" name="blogpost1" /><br />
|
||||
Post 2: <input type="file" name="blogpost2" /><br />
|
||||
Post 3: <input type="file" name="blogpost3" /><br />
|
||||
Post 4: <input type="file" name="blogpost4" /><br />
|
||||
Post 5: <input type="file" name="blogpost5" /><br />
|
||||
Post 6: <input type="file" name="blogpost6" /><br />
|
||||
Post 7: <input type="file" name="blogpost7" /><br />
|
||||
Post 8: <input type="file" name="blogpost8" /><br />
|
||||
Post 9: <input type="file" name="blogpost9" /><br />
|
||||
<span class="b_importField">Blog metadata 0:</span> <input class="b_importField" type="file" name="blogmeta0" /><br />
|
||||
<span class="b_importField">Blog metadata 1:</span> <input class="b_importField" type="file" name="blogmeta1" /><br />
|
||||
<span class="b_importField">Post 0:</span> <input class="b_importField" type="file" name="blogpost0" /><br />
|
||||
<span class="b_importField">Post 1:</span> <input class="b_importField" type="file" name="blogpost1" /><br />
|
||||
<span class="b_importField">Post 2:</span> <input class="b_importField" type="file" name="blogpost2" /><br />
|
||||
<span class="b_importField">Post 3:</span> <input class="b_importField" type="file" name="blogpost3" /><br />
|
||||
<span class="b_importField">Post 4:</span> <input class="b_importField" type="file" name="blogpost4" /><br />
|
||||
<span class="b_importField">Post 5:</span> <input class="b_importField" type="file" name="blogpost5" /><br />
|
||||
<span class="b_importField">Post 6:</span> <input class="b_importField" type="file" name="blogpost6" /><br />
|
||||
<span class="b_importField">Post 7:</span> <input class="b_importField" type="file" name="blogpost7" /><br />
|
||||
<span class="b_importField">Post 8:</span> <input class="b_importField" type="file" name="blogpost8" /><br />
|
||||
<span class="b_importField">Post 9:</span> <input class="b_importField" type="file" name="blogpost9" /><br />
|
||||
<hr />
|
||||
<input type="submit" name="Post" value="Post entry" /> <input type="reset" value="Cancel" />
|
||||
<input class="b_importSubmit" type="submit" name="Post" value="Post entry" /> <input class="b_importCancel" type="reset" value="Cancel" />
|
||||
<% } %>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
@ -1,16 +1,27 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<%@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="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><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3"><jsp:include page="_bodyindex.jsp" /></td></tr>
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><jsp:include page="_bodyindex.jsp" /></td></tr>
|
||||
</table>
|
||||
</body>
|
@ -1,31 +1,34 @@
|
||||
<%@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.*" %>
|
||||
<% 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" />
|
||||
<%@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</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" />
|
||||
<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><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3"><%
|
||||
<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()) {
|
||||
%>You must be logged in to post<%
|
||||
%><span class="b_postMsgErr">You must be logged in to post</span><%
|
||||
} else {
|
||||
String confirm = request.getParameter("confirm");
|
||||
if ( (confirm != null) && (confirm.equalsIgnoreCase("true")) ) {
|
||||
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) {
|
||||
%>Blog entry <a href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, uri.getEntryId(), -1, -1,
|
||||
user.getShowExpanded(), user.getShowImages())%>">posted</a>!<%
|
||||
%><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 {
|
||||
%>There was an unknown error posting the entry...<%
|
||||
%><span class="b_postMsgErro">There was an unknown error posting the entry...</span><%
|
||||
}
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
@ -43,17 +46,34 @@ if (!user.getAuthenticated()) {
|
||||
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);
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r);
|
||||
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.get((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);
|
||||
@ -76,16 +96,42 @@ if (!user.getAuthenticated()) {
|
||||
}
|
||||
|
||||
post.renderPreview(out);
|
||||
%><hr />Please <a href="post.jsp?confirm=true">confirm</a> that this is ok. Otherwise, just go back and make changes.<%
|
||||
%><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.get(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
|
||||
%><form action="post.jsp" method="POST" enctype="multipart/form-data">
|
||||
Post subject: <input type="text" size="80" name="entrysubject" value="<%=post.getSubject()%>" /><br />
|
||||
Post tags: <input type="text" size="20" name="entrytags" value="<%=post.getTags()%>" /><br />
|
||||
Post content (in raw SML, no headers):<br />
|
||||
<textarea rows="6" cols="80" name="entrytext"><%=post.getText()%></textarea><br />
|
||||
<b>SML cheatsheet:</b><br /><textarea rows="6" cols="80" readonly="true">
|
||||
<span class="b_postField">Post subject:</span> <input class="b_postSubject" type="text" size="80" name="entrysubject" value="<%=post.getSubject()%>" /><br />
|
||||
<span class="b_postField">Post tags:</span> <input class="b_postTags" type="text" size="20" name="entrytags" value="<%=post.getTags()%>" /><br />
|
||||
<span class="b_postField">Post style:</span> <select class="b_postStyle" name="style">
|
||||
<option value="default" selected="true">Default</option>
|
||||
<option value="meta">Meta (hide everything but the metadata)</option>
|
||||
</select><br />
|
||||
<span class="b_postField">Include public names?</span> <input class="b_postNames" type="checkbox" name="includenames" value="true" /><br />
|
||||
<span class="b_postField">Post content (in raw SML, no headers):</span><br />
|
||||
<textarea class="b_postText" rows="6" cols="80" name="entrytext"><%=post.getText()%></textarea><br />
|
||||
<span class="b_postField">SML cheatsheet:</span><br /><textarea class="b_postCheatsheet" rows="6" cols="80" readonly="true">
|
||||
* newlines are newlines are newlines.
|
||||
* all < and > are replaced with their &symbol;
|
||||
* [b][/b] = <b>bold</b>
|
||||
@ -100,30 +146,23 @@ Post content (in raw SML, no headers):<br />
|
||||
* [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)
|
||||
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 />
|
||||
SML post headers:<br />
|
||||
<textarea rows="3" cols="80" name="entryheaders"><%=post.getHeaders()%></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)%>" />
|
||||
<% } %>
|
||||
|
||||
Attachment 0: <input type="file" name="entryfile0" /><br />
|
||||
Attachment 1: <input type="file" name="entryfile1" /><br />
|
||||
Attachment 2: <input type="file" name="entryfile2" /><br />
|
||||
Attachment 3: <input type="file" name="entryfile3" /><br /><!--
|
||||
Attachment 4: <input type="file" name="entryfile4" /><br />
|
||||
Attachment 5: <input type="file" name="entryfile5" /><br />
|
||||
Attachment 6: <input type="file" name="entryfile6" /><br />
|
||||
Attachment 7: <input type="file" name="entryfile7" /><br />
|
||||
Attachment 8: <input type="file" name="entryfile8" /><br />
|
||||
Attachment 9: <input type="file" name="entryfile9" /><br />-->
|
||||
<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 type="submit" name="Post" value="Preview..." /> <input type="reset" value="Cancel" />
|
||||
<input class="b_postPreview" type="submit" name="Post" value="Preview..." /> <input class="b_postReset" type="reset" value="Cancel" />
|
||||
<%
|
||||
} // end of the 'logged in, not confirmed, nothing posted' section
|
||||
} // end of the 'logged in, not confirmed' section
|
||||
|
@ -1,18 +1,19 @@
|
||||
<%@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.*" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<%@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.*" %><%
|
||||
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</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" />
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" colspan="3"><%
|
||||
<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"><%
|
||||
String regLogin = request.getParameter("login");
|
||||
boolean showForm = true;
|
||||
if ( (regLogin != null) && ("Register".equals(request.getParameter("Register"))) ) {
|
||||
@ -23,25 +24,25 @@ if ( (regLogin != null) && ("Register".equals(request.getParameter("Register")))
|
||||
String url = request.getParameter("contacturl");
|
||||
String regResult = BlogManager.instance().register(user, regLogin, regUserPass, regPass, blogName, desc, url);
|
||||
if (User.LOGIN_OK.equals(regResult)) {
|
||||
out.print("<b>Registration successful.</b> <a href=\"index.jsp\">Continue...</a>\n");
|
||||
showForm = false;
|
||||
%><span class="b_regMsgOk">Registration successful.</span> <a class="b_reg" href="index.jsp">Continue...</a>
|
||||
<% showForm = false;
|
||||
} else {
|
||||
out.print("<b>" + regResult + "</b>");
|
||||
%><span class="b_regMsgErr"><%=regResult%></span><%
|
||||
}
|
||||
}
|
||||
if (showForm) {%><form action="register.jsp" method="POST">
|
||||
<p>To create a new blog (and Syndie user account), please fill out the following form.
|
||||
<p class="b_reg">To create a new blog (and Syndie user account), please fill out the following form.
|
||||
You may need to enter a registration password given to you by this Syndie instance's
|
||||
operator, or there may be no registration password in place (in which case you can
|
||||
leave that field blank).</p>
|
||||
<p>
|
||||
<b>Syndie login:</b> <input type="text" size="8" name="login" /><br />
|
||||
<b>New password:</b> <input type="password" size="8" name="password" /><br />
|
||||
<b>Registration password:</b> <input type="password" size="8" name="registrationpassword" /><br />
|
||||
<b>Blog name:</b> <input type="text" size="32" name="blogname" /><br />
|
||||
<b>Brief description:</b> <input type="text" size="60" name="description" /><br />
|
||||
<b>Contact URL:</b> <input type="text" size="20" name="contacturl" /> <i>(e.g. mailto://user@mail.i2p, http://foo.i2p/, etc)</i><br />
|
||||
<input type="submit" name="Register" value="Register" />
|
||||
<p class="b_reg">
|
||||
<em class="b_regField">Syndie login:</em> <input class="b_regField" type="text" size="8" name="login" /><br />
|
||||
<em class="b_regField">New password:</em> <input class="b_regField" type="password" size="8" name="password" /><br />
|
||||
<em class="b_regField">Registration password:</em> <input class="b_regField" type="password" size="8" name="registrationpassword" /><br />
|
||||
<em class="b_regField">Blog name:</em> <input class="b_regField" type="text" size="32" name="blogname" /><br />
|
||||
<em class="b_regField">Brief description:</em> <input class="b_regField" type="text" size="60" name="description" /><br />
|
||||
<em class="b_regField">Contact URL:</em> <input class="b_regField" type="text" size="20" name="contacturl" /> <span class="b_reg">(e.g. mailto://user@mail.i2p, http://foo.i2p/, etc)</span><br />
|
||||
<input class="b_regSubmit" type="submit" name="Register" value="Register" />
|
||||
</p>
|
||||
</form><% } %>
|
||||
</td></tr>
|
||||
|
@ -1,37 +1,54 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*" %>
|
||||
<% 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" />
|
||||
<%@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</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" />
|
||||
<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><td colspan="5" valign="top" align="left"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<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"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr><form action="remote.jsp" method="POST"><td valign="top" align="left" colspan="3">
|
||||
<%
|
||||
if (!user.getAuthenticated() || !user.getAllowAccessRemote()) {
|
||||
%>Sorry, you are not allowed to access remote archives from here. Perhaps you should install Syndie yourself?<%
|
||||
} else { %>Import from:
|
||||
<select name="schema">
|
||||
<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>
|
||||
Proxy <input type="text" size="10" name="proxyhost" value="localhost" />:<input type="text" size="4" name="proxyport" value="4444" />
|
||||
<input name="location" size="40" value="<%=(request.getParameter("location") != null ? request.getParameter("location") : "")%>" />
|
||||
<input type="submit" name="action" value="Continue..." /><br />
|
||||
<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().getNames().iterator(); iter.hasNext(); ) {
|
||||
PetName pn = user.getPetNameDB().get((String)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)) {
|
||||
remote.fetchIndex(user, request.getParameter("schema"), request.getParameter("location"), request.getParameter("proxyhost"), request.getParameter("proxyport"));
|
||||
String location = request.getParameter("location");
|
||||
String pn = request.getParameter("archivepetname");
|
||||
if ( (pn != null) && (pn.trim().length() > 0) ) {
|
||||
PetName pnval = user.getPetNameDB().get(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)) {
|
||||
@ -44,20 +61,20 @@ Proxy <input type="text" size="10" name="proxyhost" value="localhost" />:<input
|
||||
remote.postSelectedEntries(user, request.getParameterMap());
|
||||
}
|
||||
String msgs = remote.getStatus();
|
||||
if ( (msgs != null) && (msgs.length() > 0) ) { %><pre><%=msgs%>
|
||||
<a href="remote.jsp">Refresh</a></pre><br /><%
|
||||
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()) { %><b>Please wait while the index is being fetched
|
||||
from <%=remote.getRemoteLocation()%></b>. <%
|
||||
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!
|
||||
%><b><%=remote.getRemoteLocation()%></b>
|
||||
<a href="remote.jsp?schema=<%=remote.getRemoteSchema()%>&location=<%=remote.getRemoteLocation()%><%
|
||||
%><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 style="font-size:8pt" rows="5" cols="120"><%=remote.getRemoteIndex()%></textarea><%
|
||||
<textarea class="b_remoteIndex" rows="5" cols="120"><%=remote.getRemoteIndex()%></textarea><%
|
||||
}
|
||||
}
|
||||
%>
|
||||
|
@ -1,3 +1,7 @@
|
||||
<%@page contentType="text/css; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@page contentType="text/css; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.util.FileUtil" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<%@include file="syndie.css" %>
|
||||
<%@include file="syndie.css" %>
|
||||
<%
|
||||
String content = FileUtil.readTextFile("./docs/syndie_standard.css", -1, true);
|
||||
if (content != null) out.write(content);
|
||||
%>
|