Compare commits
76 Commits
i2p_0_6_0_
...
i2p_0_6_0_
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
3e51584b3c | ||
![]() |
4ff8a53084 | ||
![]() |
ccb73437c4 | ||
![]() |
b43114f61b | ||
![]() |
9bd87ab511 | ||
![]() |
b6ea55f7ef | ||
![]() |
5f18cec97d | ||
![]() |
3ba921ec0e | ||
![]() |
e313da254c | ||
![]() |
8660cf0d74 | ||
![]() |
e0bfdff152 | ||
![]() |
c27aed3603 | ||
![]() |
cdc6002f0e | ||
![]() |
4cf3d9c1a2 | ||
![]() |
0473e08e21 | ||
![]() |
346faa3de2 | ||
![]() |
5ec6dca64d | ||
![]() |
1a6b49cfb8 | ||
![]() |
c7b75df390 | ||
![]() |
f97c09291b |
@@ -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,49 @@ 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 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 +64,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
public void write(byte buf[], int off, int len) throws IOException {
|
||||
if (_headerWritten) {
|
||||
out.write(buf, off, len);
|
||||
_dataWritten += len;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,8 +76,11 @@ 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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -128,7 +145,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 +156,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 +174,85 @@ 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 _in;
|
||||
private OutputStream _out;
|
||||
public Pusher(InputStream in, OutputStream out) {
|
||||
_in = in;
|
||||
_out = out;
|
||||
}
|
||||
public void run() {
|
||||
OutputStream to = null;
|
||||
InternalGZIPInputStream in = null;
|
||||
long start = System.currentTimeMillis();
|
||||
long written = 0;
|
||||
try {
|
||||
in = new InternalGZIPInputStream(_in);
|
||||
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.getTotalRead() + "/" + in.getTotalExpanded(), ioe);
|
||||
} finally {
|
||||
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
long compressed = in.getTotalRead();
|
||||
long expanded = in.getTotalExpanded();
|
||||
double ratio = 0;
|
||||
if (expanded > 0)
|
||||
ratio = compressed/expanded;
|
||||
|
||||
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), end-start);
|
||||
_context.statManager().addRateData("i2ptunnel.httpCompressed", compressed, end-start);
|
||||
_context.statManager().addRateData("i2ptunnel.httpExpanded", 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 static void main(String args[]) {
|
||||
|
@@ -109,8 +109,9 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
_tunnelId = ++__tunnelId;
|
||||
_log = _context.logManager().getLog(I2PTunnel.class);
|
||||
_event = new EventDispatcherImpl();
|
||||
_clientOptions = new Properties();
|
||||
_clientOptions.putAll(System.getProperties());
|
||||
Properties p = new Properties();
|
||||
p.putAll(System.getProperties());
|
||||
_clientOptions = p;
|
||||
_sessions = new ArrayList(1);
|
||||
|
||||
addConnectionEventListener(lsnr);
|
||||
|
@@ -101,6 +101,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
this.l = l;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
|
||||
// no need to load the netDb with leaseSets for destinations that will never
|
||||
// be looked up
|
||||
tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
|
||||
|
||||
while (sockMgr == null) {
|
||||
synchronized (sockLock) {
|
||||
if (ownDest) {
|
||||
|
@@ -369,6 +369,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
if (line.length() == 0) {
|
||||
|
||||
String ok = getTunnel().getContext().getProperty("i2ptunnel.gzip");
|
||||
boolean gzip = false;
|
||||
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,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 {
|
||||
@@ -60,14 +61,45 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
socket.setReadTimeout(readTimeout);
|
||||
String modifiedHeader = getModifiedHeader(socket);
|
||||
// give them 5 seconds to send in the HTTP request
|
||||
socket.setReadTimeout(5*1000);
|
||||
|
||||
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");
|
||||
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;
|
||||
}
|
||||
String enc = headers.getProperty("Accept-encoding");
|
||||
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();
|
||||
@@ -86,17 +118,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[4096];
|
||||
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');
|
||||
@@ -131,6 +265,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 + "]");
|
||||
|
@@ -11,6 +11,7 @@ import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.ConnectException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -39,6 +40,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
protected InetAddress remoteHost;
|
||||
protected int remotePort;
|
||||
private boolean _usePool;
|
||||
|
||||
private Logging l;
|
||||
|
||||
@@ -46,15 +48,27 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
/** default timeout to 3 minutes - override if desired */
|
||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
private static final boolean DEFAULT_USE_POOL = false;
|
||||
|
||||
public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host + ":" + port + " <- " + privData, notifyThis, tunnel);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData));
|
||||
String usePool = tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
init(host, port, bais, privData, l);
|
||||
}
|
||||
|
||||
public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel);
|
||||
String usePool = tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
try {
|
||||
init(host, port, new FileInputStream(privkey), privkeyname, l);
|
||||
} catch (IOException ioe) {
|
||||
@@ -65,6 +79,11 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel);
|
||||
String usePool = tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
init(host, port, privData, privkeyname, l);
|
||||
}
|
||||
|
||||
@@ -178,22 +197,34 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (shouldUsePool()) {
|
||||
I2PServerSocket i2pss = sockMgr.getServerSocket();
|
||||
int handlers = getHandlerCount();
|
||||
for (int i = 0; i < handlers; i++) {
|
||||
I2PThread handler = new I2PThread(new Handler(i2pss), "Handle Server " + i);
|
||||
handler.start();
|
||||
}
|
||||
/*
|
||||
} else {
|
||||
I2PServerSocket i2pss = sockMgr.getServerSocket();
|
||||
while (true) {
|
||||
I2PSocket i2ps = i2pss.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
I2PThread t = new I2PThread(new Handler(i2ps));
|
||||
t.start();
|
||||
try {
|
||||
final I2PSocket i2ps = i2pss.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
new I2PThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start();
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
return;
|
||||
} catch (ConnectException ce) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting", ce);
|
||||
// not killing the server..
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldUsePool() { return _usePool; }
|
||||
|
||||
/**
|
||||
* minor thread pool to pull off the accept() concurrently. there are still lots
|
||||
|
@@ -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>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?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">
|
||||
@@ -14,4 +14,4 @@
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
@@ -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);
|
||||
|
@@ -20,6 +20,7 @@ public class FormHandler {
|
||||
protected Log _log;
|
||||
private String _nonce;
|
||||
protected String _action;
|
||||
protected String _passphrase;
|
||||
private List _errors;
|
||||
private List _notices;
|
||||
private boolean _processed;
|
||||
@@ -32,6 +33,7 @@ public class FormHandler {
|
||||
_processed = false;
|
||||
_valid = true;
|
||||
_nonce = null;
|
||||
_passphrase = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +53,7 @@ public class FormHandler {
|
||||
|
||||
public void setNonce(String val) { _nonce = val; }
|
||||
public void setAction(String val) { _action = val; }
|
||||
public void setPassphrase(String val) { _passphrase = val; }
|
||||
|
||||
/**
|
||||
* Override this to perform the final processing (in turn, adding formNotice
|
||||
@@ -119,8 +122,14 @@ public class FormHandler {
|
||||
String noncePrev = System.getProperty(getClass().getName() + ".noncePrev");
|
||||
if ( ( (nonce == null) || (!_nonce.equals(nonce)) ) &&
|
||||
( (noncePrev == null) || (!_nonce.equals(noncePrev)) ) ) {
|
||||
addFormError("Invalid nonce, are you being spoofed?");
|
||||
_valid = false;
|
||||
|
||||
String expected = _context.getProperty("consolePassword");
|
||||
if ( (expected != null) && (expected.trim().length() > 0) && (expected.equals(_passphrase)) ) {
|
||||
// ok
|
||||
} else {
|
||||
addFormError("Invalid nonce, are you being spoofed?");
|
||||
_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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) {}
|
||||
}
|
||||
|
@@ -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;
|
||||
@@ -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,34 @@
|
||||
<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 through NAT hole punching? </b>
|
||||
<input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
|
||||
<p>If you can't poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach the
|
||||
router, as detected with the <i>Status: ERR-Reject</i>, then you will need SSU introductions.
|
||||
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 /><%
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?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">
|
||||
@@ -14,4 +14,4 @@
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
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="UTF-8"?>
|
||||
<!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="UTF-8"?>
|
||||
<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.22 $
|
||||
*/
|
||||
%>
|
||||
<%@ 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>
|
@@ -14,7 +14,7 @@
|
||||
srcdir="./src"
|
||||
debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="./build/obj"
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar" />
|
||||
</target>
|
||||
<target name="jar" depends="builddep, compile">
|
||||
<jar destfile="./build/syndie.jar" basedir="./build/obj" includes="**/*.class">
|
||||
@@ -46,6 +46,7 @@
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/ant.jar" />
|
||||
<pathelement location="build/obj" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
@@ -67,6 +68,7 @@
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="build/obj" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
</classpath>
|
||||
|
@@ -30,6 +30,7 @@ public class Archive {
|
||||
private Map _blogInfo;
|
||||
private ArchiveIndex _index;
|
||||
private EntryExtractor _extractor;
|
||||
private String _defaultSelector;
|
||||
|
||||
public static final String METADATA_FILE = "meta.snm";
|
||||
public static final String INDEX_FILE = "archive.txt";
|
||||
@@ -50,6 +51,8 @@ public class Archive {
|
||||
_blogInfo = new HashMap();
|
||||
_index = null;
|
||||
_extractor = new EntryExtractor(ctx);
|
||||
_defaultSelector = ctx.getProperty("syndie.defaultSelector");
|
||||
if (_defaultSelector == null) _defaultSelector = "";
|
||||
reloadInfo();
|
||||
}
|
||||
|
||||
@@ -63,7 +66,13 @@ public class Archive {
|
||||
BlogInfo bi = new BlogInfo();
|
||||
try {
|
||||
bi.load(new FileInputStream(meta));
|
||||
info.add(bi);
|
||||
if (bi.verify(_context)) {
|
||||
info.add(bi);
|
||||
} else {
|
||||
System.err.println("Invalid blog (but we're storing it anyway): " + bi);
|
||||
new Exception("foo").printStackTrace();
|
||||
info.add(bi);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
@@ -79,8 +88,17 @@ 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;
|
||||
synchronized (_blogInfo) {
|
||||
return (BlogInfo)_blogInfo.get(uri.getKeyHash());
|
||||
}
|
||||
@@ -90,14 +108,21 @@ public class Archive {
|
||||
return (BlogInfo)_blogInfo.get(key);
|
||||
}
|
||||
}
|
||||
public void storeBlogInfo(BlogInfo info) {
|
||||
public boolean storeBlogInfo(BlogInfo info) {
|
||||
if (!info.verify(_context)) {
|
||||
System.err.println("Not storing the invalid blog " + info);
|
||||
return;
|
||||
new Exception("foo!").printStackTrace();
|
||||
return false;
|
||||
}
|
||||
boolean isNew = true;
|
||||
synchronized (_blogInfo) {
|
||||
_blogInfo.put(info.getKey().calculateHash(), info);
|
||||
BlogInfo old = (BlogInfo)_blogInfo.get(info.getKey().calculateHash());
|
||||
if ( (old == null) || (old.getEdition() < info.getEdition()) )
|
||||
_blogInfo.put(info.getKey().calculateHash(), info);
|
||||
else
|
||||
isNew = false;
|
||||
}
|
||||
if (!isNew) return true; // valid entry, but not stored, since its old
|
||||
try {
|
||||
File blogDir = new File(_rootDir, info.getKey().calculateHash().toBase64());
|
||||
blogDir.mkdirs();
|
||||
@@ -106,8 +131,10 @@ public class Archive {
|
||||
info.write(out);
|
||||
out.close();
|
||||
System.out.println("Blog info written to " + blogFile.getPath());
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,13 +169,17 @@ public class Archive {
|
||||
for (int j = 0; j < entries.length; j++) {
|
||||
try {
|
||||
File entryDir = getEntryDir(entries[j]);
|
||||
if (!entryDir.exists()) {
|
||||
EntryContainer entry = null;
|
||||
if (entryDir.exists())
|
||||
entry = getCachedEntry(entryDir);
|
||||
if ( (entry == null) || (!entryDir.exists()) ) {
|
||||
if (!extractEntry(entries[j], entryDir, info)) {
|
||||
System.err.println("Entry " + entries[j].getPath() + " is not valid");
|
||||
new Exception("foo!!").printStackTrace();
|
||||
continue;
|
||||
}
|
||||
entry = getCachedEntry(entryDir);
|
||||
}
|
||||
EntryContainer entry = getCachedEntry(entryDir);
|
||||
String tags[] = entry.getTags();
|
||||
for (int t = 0; t < tags.length; t++) {
|
||||
if (!rv.contains(tags[t])) {
|
||||
@@ -183,7 +214,20 @@ public class Archive {
|
||||
}
|
||||
|
||||
private EntryContainer getCachedEntry(File entryDir) {
|
||||
return new CachedEntry(entryDir);
|
||||
try {
|
||||
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;
|
||||
}
|
||||
|
||||
public EntryContainer getEntry(BlogURI uri) { return getEntry(uri, null); }
|
||||
@@ -214,13 +258,16 @@ public class Archive {
|
||||
if (blogKey == null) {
|
||||
// no key, cache.
|
||||
File entryDir = getEntryDir(entries[i]);
|
||||
if (!entryDir.exists()) {
|
||||
if (entryDir.exists())
|
||||
entry = getCachedEntry(entryDir);
|
||||
if ((entry == null) || !entryDir.exists()) {
|
||||
if (!extractEntry(entries[i], entryDir, info)) {
|
||||
System.err.println("Entry " + entries[i].getPath() + " is not valid");
|
||||
new Exception("foo!!!!").printStackTrace();
|
||||
continue;
|
||||
}
|
||||
entry = getCachedEntry(entryDir);
|
||||
}
|
||||
entry = getCachedEntry(entryDir);
|
||||
} else {
|
||||
// we have an explicit key - no caching
|
||||
entry = new EntryContainer();
|
||||
@@ -228,6 +275,7 @@ public class Archive {
|
||||
boolean ok = entry.verifySignature(_context, info);
|
||||
if (!ok) {
|
||||
System.err.println("Keyed entry " + entries[i].getPath() + " is not valid");
|
||||
new Exception("foo!!!!!!").printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -262,7 +310,16 @@ public class Archive {
|
||||
}
|
||||
|
||||
public boolean storeEntry(EntryContainer container) {
|
||||
if (container == null) return false;
|
||||
BlogURI uri = container.getURI();
|
||||
if (uri == null) return false;
|
||||
|
||||
File blogDir = new File(_rootDir, uri.getKeyHash().toBase64());
|
||||
blogDir.mkdirs();
|
||||
File entryFile = new File(blogDir, getEntryFilename(uri.getEntryId()));
|
||||
if (entryFile.exists()) return true;
|
||||
|
||||
|
||||
BlogInfo info = getBlogInfo(uri);
|
||||
if (info == null) {
|
||||
System.out.println("no blog metadata for the uri " + uri);
|
||||
@@ -274,13 +331,10 @@ public class Archive {
|
||||
} else {
|
||||
//System.out.println("Signature is valid: " + container.getSignature() + " for info " + info);
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
container.write(baos, true);
|
||||
File blogDir = new File(_rootDir, uri.getKeyHash().toBase64());
|
||||
blogDir.mkdirs();
|
||||
byte data[] = baos.toByteArray();
|
||||
File entryFile = new File(blogDir, getEntryFilename(uri.getEntryId()));
|
||||
FileOutputStream out = new FileOutputStream(entryFile);
|
||||
out.write(data);
|
||||
out.close();
|
||||
@@ -294,7 +348,7 @@ public class Archive {
|
||||
|
||||
public static String getEntryFilename(long entryId) { return entryId + ".snd"; }
|
||||
|
||||
private static SimpleDateFormat _dateFmt = new SimpleDateFormat("yyyyMMdd");
|
||||
private static SimpleDateFormat _dateFmt = new SimpleDateFormat("yyyyMMdd", Locale.UK);
|
||||
public static String getIndexName(long entryId, int numBytes) {
|
||||
try {
|
||||
synchronized (_dateFmt) {
|
||||
@@ -364,8 +418,8 @@ public class Archive {
|
||||
reloadInfo();
|
||||
_index = ArchiveIndexer.index(_context, this);
|
||||
try {
|
||||
PrintWriter out = new PrintWriter(new FileWriter(new File(_rootDir, INDEX_FILE)));
|
||||
out.println(_index.toString());
|
||||
FileOutputStream out = new FileOutputStream(new File(_rootDir, INDEX_FILE));
|
||||
out.write(DataHelper.getUTF8(_index.toString()));
|
||||
out.flush();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
|
@@ -6,6 +6,7 @@ import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
import net.i2p.syndie.sml.*;
|
||||
|
||||
/**
|
||||
* Dig through the archive to build an index
|
||||
@@ -15,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();
|
||||
@@ -23,7 +24,7 @@ class ArchiveIndexer {
|
||||
File headerFile = new File(rootDir, Archive.HEADER_FILE);
|
||||
if (headerFile.exists()) {
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(headerFile)));
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(headerFile), "UTF-8"));
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
StringTokenizer tok = new StringTokenizer(line, ":");
|
||||
@@ -53,6 +54,8 @@ class ArchiveIndexer {
|
||||
long totalSize = 0;
|
||||
int newBlogs = 0;
|
||||
|
||||
SMLParser parser = new SMLParser(ctx);
|
||||
|
||||
for (int i = 0; i < blogs.size(); i++) {
|
||||
BlogInfo cur = (BlogInfo)blogs.get(i);
|
||||
Hash key = cur.getKey().calculateHash();
|
||||
@@ -76,6 +79,7 @@ class ArchiveIndexer {
|
||||
for (int t = 0; t < entryTags.length; t++) {
|
||||
if (!tags.containsKey(entryTags[t])) {
|
||||
tags.put(entryTags[t], new TreeMap());
|
||||
//System.err.println("New tag [" + entryTags[t] + "]");
|
||||
}
|
||||
Map entriesByTag = (Map)tags.get(entryTags[t]);
|
||||
entriesByTag.put(new Long(0-entry.getURI().getEntryId()), entry);
|
||||
@@ -86,6 +90,16 @@ class ArchiveIndexer {
|
||||
newEntries++;
|
||||
newSize += entry.getCompleteSize();
|
||||
}
|
||||
HeaderReceiver rec = new HeaderReceiver();
|
||||
parser.parse(entry.getEntry().getText(), rec);
|
||||
String reply = rec.getHeader(HTMLRenderer.HEADER_IN_REPLY_TO);
|
||||
if (reply != null) {
|
||||
BlogURI parent = new BlogURI(reply.trim());
|
||||
if ( (parent.getKeyHash() != null) && (parent.getEntryId() >= 0) )
|
||||
rv.addReply(parent, entry.getURI());
|
||||
else
|
||||
System.err.println("Parent of " + entry.getURI() + " is not valid: [" + reply.trim() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
long lowestEntryId = -1;
|
||||
@@ -134,4 +148,43 @@ class ArchiveIndexer {
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static class HeaderReceiver implements SMLParser.EventReceiver {
|
||||
private Properties _headers;
|
||||
public HeaderReceiver() { _headers = null; }
|
||||
public String getHeader(String name) { return (_headers != null ? _headers.getProperty(name) : null); }
|
||||
public void receiveHeader(String header, String value) {
|
||||
if (_headers == null) _headers = new Properties();
|
||||
_headers.setProperty(header, value);
|
||||
}
|
||||
|
||||
public void receiveAddress(String name, String schema, String protocol, String location, String anchorText) {}
|
||||
public void receiveArchive(String name, String description, String locationSchema, String location, String postingKey, String anchorText) {}
|
||||
public void receiveAttachment(int id, String anchorText) {}
|
||||
public void receiveBegin() {}
|
||||
public void receiveBlog(String name, String blogKeyHash, String blogPath, long blogEntryId, List blogArchiveLocations, String anchorText) {}
|
||||
public void receiveBold(String text) {}
|
||||
public void receiveCode(String text, String codeLocationSchema, String codeLocation) {}
|
||||
public void receiveCut(String summaryText) {}
|
||||
public void receiveEnd() {}
|
||||
public void receiveGT() {}
|
||||
public void receiveH1(String text) {}
|
||||
public void receiveH2(String text) {}
|
||||
public void receiveH3(String text) {}
|
||||
public void receiveH4(String text) {}
|
||||
public void receiveH5(String text) {}
|
||||
public void receiveHR() {}
|
||||
public void receiveHeaderEnd() {}
|
||||
public void receiveImage(String alternateText, int attachmentId) {}
|
||||
public void receiveItalic(String text) {}
|
||||
public void receiveLT() {}
|
||||
public void receiveLeftBracket() {}
|
||||
public void receiveLink(String schema, String location, String text) {}
|
||||
public void receiveNewline() {}
|
||||
public void receivePlain(String text) {}
|
||||
public void receivePre(String text) {}
|
||||
public void receiveQuote(String text, String whoQuoted, String quoteLocationSchema, String quoteLocation) {}
|
||||
public void receiveRightBracket() {}
|
||||
public void receiveUnderline(String text) {}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
@@ -18,39 +19,87 @@ public class BlogManager {
|
||||
private File _archiveDir;
|
||||
private File _userDir;
|
||||
private File _cacheDir;
|
||||
private File _tempDir;
|
||||
private File _rootDir;
|
||||
private Archive _archive;
|
||||
|
||||
static {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
String rootDir = I2PAppContext.getGlobalContext().getProperty("syndie.rootDir");
|
||||
if (rootDir == null)
|
||||
rootDir = System.getProperty("user.home");
|
||||
rootDir = rootDir + File.separatorChar + ".syndie";
|
||||
if (false) {
|
||||
if (rootDir == null)
|
||||
rootDir = System.getProperty("user.home");
|
||||
rootDir = rootDir + File.separatorChar + ".syndie";
|
||||
} else {
|
||||
if (rootDir == null)
|
||||
rootDir = "./syndie";
|
||||
}
|
||||
_instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir);
|
||||
}
|
||||
public static BlogManager instance() { return _instance; }
|
||||
|
||||
public BlogManager(I2PAppContext ctx, String rootDir) {
|
||||
_context = ctx;
|
||||
File root = new File(rootDir);
|
||||
root.mkdirs();
|
||||
_blogKeyDir = new File(root, "blogkeys");
|
||||
_privKeyDir = new File(root, "privkeys");
|
||||
_rootDir = new File(rootDir);
|
||||
_rootDir.mkdirs();
|
||||
readConfig();
|
||||
_blogKeyDir = new File(_rootDir, "blogkeys");
|
||||
_privKeyDir = new File(_rootDir, "privkeys");
|
||||
String archiveDir = _context.getProperty("syndie.archiveDir");
|
||||
if (archiveDir != null)
|
||||
_archiveDir = new File(archiveDir);
|
||||
else
|
||||
_archiveDir = new File(root, "archive");
|
||||
_userDir = new File(root, "users");
|
||||
_cacheDir = new File(root, "cache");
|
||||
_archiveDir = new File(_rootDir, "archive");
|
||||
_userDir = new File(_rootDir, "users");
|
||||
_cacheDir = new File(_rootDir, "cache");
|
||||
_tempDir = new File(_rootDir, "temp");
|
||||
_blogKeyDir.mkdirs();
|
||||
_privKeyDir.mkdirs();
|
||||
_archiveDir.mkdirs();
|
||||
_cacheDir.mkdirs();
|
||||
_userDir.mkdirs();
|
||||
_tempDir.mkdirs();
|
||||
_archive = new Archive(ctx, _archiveDir.getAbsolutePath(), _cacheDir.getAbsolutePath());
|
||||
_archive.regenerateIndex();
|
||||
}
|
||||
|
||||
private File getConfigFile() { return new File(_rootDir, "syndie.config"); }
|
||||
private void readConfig() {
|
||||
File config = getConfigFile();
|
||||
if (config.exists()) {
|
||||
try {
|
||||
Properties p = new Properties();
|
||||
DataHelper.loadProps(p, config);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
public void writeConfig() {
|
||||
File config = new File(_rootDir, "syndie.config");
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(config);
|
||||
for (Iterator iter = _context.getPropertyNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
if (name.startsWith("syndie."))
|
||||
out.write(DataHelper.getUTF8(name + '=' + _context.getProperty(name) + '\n'));
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
public BlogInfo createBlog(String name, String description, String contactURL, String archives[]) {
|
||||
return createBlog(name, null, description, contactURL, archives);
|
||||
}
|
||||
@@ -93,6 +142,7 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
public Archive getArchive() { return _archive; }
|
||||
public File getTempDir() { return _tempDir; }
|
||||
|
||||
public List listMyBlogs() {
|
||||
File files[] = _privKeyDir.listFiles();
|
||||
@@ -135,14 +185,18 @@ public class BlogManager {
|
||||
}
|
||||
|
||||
public String login(User user, String login, String pass) {
|
||||
File userFile = new File(_userDir, Base64.encode(_context.sha().calculateHash(login.getBytes()).getData()));
|
||||
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()));
|
||||
System.out.println("Attempting to login to " + login + " w/ pass = " + pass
|
||||
+ ": file = " + userFile.getAbsolutePath() + " passHash = "
|
||||
+ Base64.encode(_context.sha().calculateHash(pass.getBytes()).getData()));
|
||||
+ Base64.encode(passHash.getData()));
|
||||
if (userFile.exists()) {
|
||||
try {
|
||||
Properties props = new Properties();
|
||||
BufferedReader in = new BufferedReader(new FileReader(userFile));
|
||||
FileInputStream fin = new FileInputStream(userFile);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(fin, "UTF-8"));
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
int split = line.indexOf('=');
|
||||
@@ -154,66 +208,133 @@ 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(user.getUsername().getBytes()).getData());
|
||||
String userHash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(user.getUsername())).getData());
|
||||
File userFile = new File(_userDir, userHash);
|
||||
FileWriter out = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(userFile);
|
||||
out.write("password=" + user.getHashedPassword() + "\n");
|
||||
out.write("blog=" + user.getBlog().toBase64() + "\n");
|
||||
out.write("lastid=" + user.getMostRecentEntry() + "\n");
|
||||
out.write("lastmetaedition=" + user.getLastMetaEntry() + "\n");
|
||||
out.write("lastlogin=" + user.getLastLogin() + "\n");
|
||||
out.write("addressbook=" + user.getAddressbookLocation() + "\n");
|
||||
out.write("showimages=" + user.getShowImages() + "\n");
|
||||
out.write("showexpanded=" + user.getShowExpanded() + "\n");
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("groups=");
|
||||
Map groups = user.getBlogGroups();
|
||||
for (Iterator iter = groups.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
List selectors = (List)groups.get(name);
|
||||
buf.append(name).append(':');
|
||||
for (int i = 0; i < selectors.size(); i++) {
|
||||
buf.append(selectors.get(i));
|
||||
if (i + 1 < selectors.size())
|
||||
buf.append(",");
|
||||
}
|
||||
if (iter.hasNext())
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append('\n');
|
||||
out.write(buf.toString());
|
||||
// shitlist=hash,hash,hash
|
||||
List shitlistedBlogs = user.getShitlistedBlogs();
|
||||
if (shitlistedBlogs.size() > 0) {
|
||||
buf.setLength(0);
|
||||
buf.append("shitlistedblogs=");
|
||||
for (int i = 0; i < shitlistedBlogs.size(); i++) {
|
||||
Hash blog = (Hash)shitlistedBlogs.get(i);
|
||||
buf.append(blog.toBase64());
|
||||
if (i + 1 < shitlistedBlogs.size())
|
||||
buf.append(',');
|
||||
}
|
||||
buf.append('\n');
|
||||
out.write(buf.toString());
|
||||
}
|
||||
out = new FileOutputStream(userFile);
|
||||
out.write(DataHelper.getUTF8(user.export()));
|
||||
user.getPetNameDB().store(user.getAddressbookLocation());
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
@@ -221,31 +342,38 @@ public class BlogManager {
|
||||
}
|
||||
}
|
||||
public String register(User user, String login, String password, String registrationPassword, String blogName, String blogDescription, String contactURL) {
|
||||
String hashedRegistrationPassword = getRegistrationPassword();
|
||||
if (hashedRegistrationPassword != null) {
|
||||
if (!hashedRegistrationPassword.equals(Base64.encode(_context.sha().calculateHash(registrationPassword.getBytes()).getData())))
|
||||
return "Invalid registration password";
|
||||
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 "<span class=\"b_regMsgErr\">Invalid registration password</span>";
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
return "<span class=\"b_regMsgErr\">Error registering</span>";
|
||||
}
|
||||
}
|
||||
String userHash = Base64.encode(_context.sha().calculateHash(login.getBytes()).getData());
|
||||
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(password.getBytes()).getData());
|
||||
FileWriter out = null;
|
||||
String hashedPassword = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(password)).getData());
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(userFile);
|
||||
out.write("password=" + hashedPassword + "\n");
|
||||
out.write("blog=" + Base64.encode(info.getKey().calculateHash().getData()) + "\n");
|
||||
out.write("lastid=-1\n");
|
||||
out.write("lastmetaedition=0\n");
|
||||
out.write("addressbook=userhosts-"+userHash + ".txt\n");
|
||||
out.write("showimages=false\n");
|
||||
out.write("showexpanded=false\n");
|
||||
out = new FileOutputStream(userFile);
|
||||
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
|
||||
bw.write("password=" + hashedPassword + "\n");
|
||||
bw.write("blog=" + Base64.encode(info.getKey().calculateHash().getData()) + "\n");
|
||||
bw.write("lastid=-1\n");
|
||||
bw.write("lastmetaedition=0\n");
|
||||
bw.write("addressbook=userhosts-"+userHash + ".txt\n");
|
||||
bw.write("showimages=false\n");
|
||||
bw.write("showexpanded=false\n");
|
||||
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) {}
|
||||
}
|
||||
@@ -254,6 +382,43 @@ 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>";
|
||||
Map newNames = new HashMap();
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
for (Iterator names = db.getNames().iterator(); names.hasNext(); ) {
|
||||
PetName pn = db.get((String)names.next());
|
||||
if (pn == null) continue;
|
||||
if (pn.getNetwork().equalsIgnoreCase("i2p")) {
|
||||
try {
|
||||
Destination d = new Destination(pn.getLocation().trim());
|
||||
newNames.put(pn.getName(), d);
|
||||
} catch (DataFormatException dfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
// horribly inefficient...
|
||||
for (Iterator iter = newNames.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
Destination existing = _context.namingService().lookup(name);
|
||||
if (existing == null) {
|
||||
Destination known = (Destination)newNames.get(name);
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream("userhosts.txt", true);
|
||||
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
|
||||
osw.write(name + "=" + known.toBase64() + "\n");
|
||||
osw.close();
|
||||
} 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);
|
||||
@@ -289,7 +454,7 @@ public class BlogManager {
|
||||
raw.append('\n');
|
||||
if ( (entryHeaders != null) && (entryHeaders.trim().length() > 0) ) {
|
||||
System.out.println("Entry headers: " + entryHeaders);
|
||||
BufferedReader userHeaders = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(entryHeaders.getBytes())));
|
||||
BufferedReader userHeaders = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(DataHelper.getUTF8(entryHeaders)), "UTF-8"));
|
||||
String line = null;
|
||||
while ( (line = userHeaders.readLine()) != null) {
|
||||
line = line.trim();
|
||||
@@ -306,7 +471,7 @@ public class BlogManager {
|
||||
raw.append('\n');
|
||||
raw.append(sml);
|
||||
|
||||
EntryContainer c = new EntryContainer(uri, tagList, raw.toString().getBytes());
|
||||
EntryContainer c = new EntryContainer(uri, tagList, DataHelper.getUTF8(raw));
|
||||
if ((fileNames != null) && (fileStreams != null) && (fileNames.size() == fileStreams.size()) ) {
|
||||
for (int i = 0; i < fileNames.size(); i++) {
|
||||
String name = (String)fileNames.get(i);
|
||||
@@ -347,28 +512,58 @@ public class BlogManager {
|
||||
}
|
||||
}
|
||||
|
||||
public String addAddress(User user, String name, String location, String schema) {
|
||||
if (!user.getAuthenticated()) return "Not logged in";
|
||||
/**
|
||||
* read in the syndie blog metadata file from the stream, verifying it and adding it to
|
||||
* the archive if necessary
|
||||
*
|
||||
*/
|
||||
public boolean importBlogMetadata(InputStream metadataStream) throws IOException {
|
||||
try {
|
||||
BlogInfo info = new BlogInfo();
|
||||
info.load(metadataStream);
|
||||
return _archive.storeBlogInfo(info);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read in the syndie entry file from the stream, verifying it and adding it to
|
||||
* the archive if necessary
|
||||
*
|
||||
*/
|
||||
public boolean importBlogEntry(InputStream entryStream) throws IOException {
|
||||
try {
|
||||
EntryContainer c = new EntryContainer();
|
||||
c.load(entryStream);
|
||||
return _archive.storeEntry(c);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
FileWriter 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 FileWriter(userHostsFile, true);
|
||||
out.write(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>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +587,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) )
|
||||
@@ -403,30 +598,40 @@ 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 GregorianCalendar _cal = new GregorianCalendar();
|
||||
private long getDayBegin(long now) {
|
||||
synchronized (_cal) {
|
||||
_cal.setTimeInMillis(now);
|
||||
_cal.set(Calendar.MILLISECOND, 0);
|
||||
_cal.set(Calendar.SECOND, 0);
|
||||
_cal.set(Calendar.MINUTE, 0);
|
||||
_cal.set(Calendar.HOUR, 0);
|
||||
_cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
return _cal.getTimeInMillis();
|
||||
|
||||
private final SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.UK);
|
||||
private final long getDayBegin(long now) {
|
||||
synchronized (_dateFormat) {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(now));
|
||||
return _dateFormat.parse(str).getTime();
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
// wtf
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -111,12 +111,12 @@ 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 {
|
||||
File f = File.createTempFile("syndie", ".html");
|
||||
Writer out = new FileWriter(f);
|
||||
Writer out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
|
||||
renderer.render(null, mgr.getArchive(), entry, out, summaryOnly, showImages);
|
||||
out.flush();
|
||||
out.close();
|
||||
|
@@ -21,13 +21,17 @@ class CachedEntry extends EntryContainer {
|
||||
private Entry _entry;
|
||||
private Attachment _attachments[];
|
||||
|
||||
public CachedEntry(File entryDir) {
|
||||
public CachedEntry(File entryDir) throws IOException {
|
||||
_entryDir = entryDir;
|
||||
importMeta();
|
||||
_entry = new CachedEntryDetails();
|
||||
_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,19 +113,17 @@ 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 {
|
||||
in = new BufferedReader(new FileReader(propsFile));
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(propsFile), "UTF-8"));
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
int split = line.indexOf('=');
|
||||
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) {}
|
||||
}
|
||||
@@ -152,7 +160,7 @@ class CachedEntry extends EntryContainer {
|
||||
in = new FileInputStream(f);
|
||||
int read = DataHelper.read(in, buf);
|
||||
if (read != buf.length) throw new IOException("read: " + read + " file size: " + buf.length + " for " + f.getPath());
|
||||
_text = new String(buf);
|
||||
_text = DataHelper.getUTF8(buf);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -65,36 +65,36 @@ public class EntryExtractor {
|
||||
}
|
||||
}
|
||||
private void extractHeaders(EntryContainer entry, File entryDir) throws IOException {
|
||||
FileWriter out = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(new File(entryDir, HEADERS));
|
||||
out = new FileOutputStream(new File(entryDir, HEADERS));
|
||||
Map headers = entry.getHeaders();
|
||||
for (Iterator iter = headers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String k = (String)iter.next();
|
||||
String v = (String)headers.get(k);
|
||||
out.write(k.trim() + '=' + v.trim() + '\n');
|
||||
out.write(DataHelper.getUTF8(k.trim() + '=' + v.trim() + '\n'));
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
private void extractMeta(EntryContainer entry, File entryDir) throws IOException {
|
||||
FileWriter out = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(new File(entryDir, META));
|
||||
out.write("format=" + entry.getFormat() + '\n');
|
||||
out.write("size=" + entry.getCompleteSize() + '\n');
|
||||
out.write("blog=" + entry.getURI().getKeyHash().toBase64() + '\n');
|
||||
out.write("entry=" + entry.getURI().getEntryId() + '\n');
|
||||
out = new FileOutputStream(new File(entryDir, META));
|
||||
out.write(DataHelper.getUTF8("format=" + entry.getFormat() + '\n'));
|
||||
out.write(DataHelper.getUTF8("size=" + entry.getCompleteSize() + '\n'));
|
||||
out.write(DataHelper.getUTF8("blog=" + entry.getURI().getKeyHash().toBase64() + '\n'));
|
||||
out.write(DataHelper.getUTF8("entry=" + entry.getURI().getEntryId() + '\n'));
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
private void extractEntry(EntryContainer entry, File entryDir) throws IOException {
|
||||
FileWriter out = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(new File(entryDir, ENTRY));
|
||||
out.write(entry.getEntry().getText());
|
||||
out = new FileOutputStream(new File(entryDir, ENTRY));
|
||||
out.write(DataHelper.getUTF8(entry.getEntry().getText()));
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
@@ -115,16 +115,16 @@ public class EntryExtractor {
|
||||
}
|
||||
}
|
||||
private void extractAttachmentMetadata(int num, Attachment attachment, File entryDir) throws IOException {
|
||||
FileWriter out = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileWriter(new File(entryDir, ATTACHMENT_PREFIX + num + ATTACHMENT_META_SUFFIX));
|
||||
out = new FileOutputStream(new File(entryDir, ATTACHMENT_PREFIX + num + ATTACHMENT_META_SUFFIX));
|
||||
Map meta = attachment.getMeta();
|
||||
for (Iterator iter = meta.keySet().iterator(); iter.hasNext(); ) {
|
||||
String k = (String)iter.next();
|
||||
String v = (String)meta.get(k);
|
||||
out.write(k + '=' + v + '\n');
|
||||
out.write(DataHelper.getUTF8(k + '=' + v + '\n'));
|
||||
}
|
||||
out.write(ATTACHMENT_DATA_SIZE + '=' + attachment.getDataLength());
|
||||
out.write(DataHelper.getUTF8(ATTACHMENT_DATA_SIZE + '=' + attachment.getDataLength()));
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
|
172
apps/syndie/java/src/net/i2p/syndie/PetName.java
Normal file
@@ -0,0 +1,172 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PetName {
|
||||
private String _name;
|
||||
private String _network;
|
||||
private String _protocol;
|
||||
private List _groups;
|
||||
private boolean _isPublic;
|
||||
private String _location;
|
||||
|
||||
public PetName() {
|
||||
this(null, null, null, null);
|
||||
}
|
||||
public PetName(String name, String network, String protocol, String location) {
|
||||
_name = name;
|
||||
_network = network;
|
||||
_protocol = protocol;
|
||||
_location = location;
|
||||
_groups = new ArrayList();
|
||||
_isPublic = false;
|
||||
}
|
||||
/**
|
||||
* @param dbLine name:network:protocol:isPublic:group1,group2,group3:location
|
||||
*/
|
||||
public PetName(String dbLine) {
|
||||
_groups = new ArrayList();
|
||||
StringTokenizer tok = new StringTokenizer(dbLine, ":\n", true);
|
||||
int tokens = tok.countTokens();
|
||||
System.out.println("Tokens: " + tokens);
|
||||
if (tokens < 7) {
|
||||
return;
|
||||
}
|
||||
String s = tok.nextToken();
|
||||
if (":".equals(s)) {
|
||||
_name = null;
|
||||
} else {
|
||||
_name = s;
|
||||
s = tok.nextToken(); // skip past the :
|
||||
}
|
||||
s = tok.nextToken();
|
||||
if (":".equals(s)) {
|
||||
_network = null;
|
||||
} else {
|
||||
_network = s;
|
||||
s = tok.nextToken(); // skip past the :
|
||||
}
|
||||
s = tok.nextToken();
|
||||
if (":".equals(s)) {
|
||||
_protocol = null;
|
||||
} else {
|
||||
_protocol = s;
|
||||
s = tok.nextToken(); // skip past the :
|
||||
}
|
||||
s = tok.nextToken();
|
||||
if (":".equals(s)) {
|
||||
_isPublic = false;
|
||||
} else {
|
||||
if ("true".equals(s))
|
||||
_isPublic = true;
|
||||
else
|
||||
_isPublic = false;
|
||||
s = tok.nextToken(); // skip past the :
|
||||
}
|
||||
s = tok.nextToken();
|
||||
if (":".equals(s)) {
|
||||
// noop
|
||||
} else {
|
||||
StringTokenizer gtok = new StringTokenizer(s, ",");
|
||||
while (gtok.hasMoreTokens())
|
||||
_groups.add(gtok.nextToken().trim());
|
||||
s = tok.nextToken(); // skip past the :
|
||||
}
|
||||
while (tok.hasMoreTokens()) {
|
||||
if (_location == null)
|
||||
_location = tok.nextToken();
|
||||
else
|
||||
_location = _location + tok.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() { return _name; }
|
||||
public String getNetwork() { return _network; }
|
||||
public String getProtocol() { return _protocol; }
|
||||
public String getLocation() { return _location; }
|
||||
public boolean getIsPublic() { return _isPublic; }
|
||||
public int getGroupCount() { return _groups.size(); }
|
||||
public String getGroup(int i) { return (String)_groups.get(i); }
|
||||
|
||||
public void setName(String name) { _name = name; }
|
||||
public void setNetwork(String network) { _network = network; }
|
||||
public void setProtocol(String protocol) { _protocol = protocol; }
|
||||
public void setLocation(String location) { _location = location; }
|
||||
public void setIsPublic(boolean pub) { _isPublic = pub; }
|
||||
public void addGroup(String name) {
|
||||
if ( (name != null) && (name.length() > 0) && (!_groups.contains(name)) )
|
||||
_groups.add(name);
|
||||
}
|
||||
public void removeGroup(String name) { _groups.remove(name); }
|
||||
public void setGroups(String groups) {
|
||||
if (groups != null) {
|
||||
_groups.clear();
|
||||
StringTokenizer tok = new StringTokenizer(groups, ", \t");
|
||||
while (tok.hasMoreTokens())
|
||||
addGroup(tok.nextToken().trim());
|
||||
} else {
|
||||
_groups.clear();
|
||||
}
|
||||
}
|
||||
public boolean isMember(String group) {
|
||||
for (int i = 0; i < getGroupCount(); i++)
|
||||
if (getGroup(i).equals(group))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer(256);
|
||||
if (_name != null) buf.append(_name.trim());
|
||||
buf.append(':');
|
||||
if (_network != null) buf.append(_network.trim());
|
||||
buf.append(':');
|
||||
if (_protocol != null) buf.append(_protocol.trim());
|
||||
buf.append(':').append(_isPublic).append(':');
|
||||
if (_groups != null) {
|
||||
for (int i = 0; i < _groups.size(); i++) {
|
||||
buf.append(((String)_groups.get(i)).trim());
|
||||
if (i + 1 < _groups.size())
|
||||
buf.append(',');
|
||||
}
|
||||
}
|
||||
buf.append(':');
|
||||
if (_location != null) buf.append(_location.trim());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if ( (obj == null) || !(obj instanceof PetName) ) return false;
|
||||
PetName pn = (PetName)obj;
|
||||
return DataHelper.eq(_name, pn._name) &&
|
||||
DataHelper.eq(_location, pn._location) &&
|
||||
DataHelper.eq(_network, pn._network) &&
|
||||
DataHelper.eq(_protocol, pn._protocol);
|
||||
}
|
||||
public int hashCode() {
|
||||
int rv = 0;
|
||||
rv += DataHelper.hashCode(_name);
|
||||
rv += DataHelper.hashCode(_location);
|
||||
rv += DataHelper.hashCode(_network);
|
||||
rv += DataHelper.hashCode(_protocol);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
test("a:b:c:true:e:f");
|
||||
test("a:::true::d");
|
||||
test("a:::true::");
|
||||
test("a:b::true::");
|
||||
test(":::trye::");
|
||||
test("a:b:c:true:e:http://foo.bar");
|
||||
}
|
||||
private static void test(String line) {
|
||||
PetName pn = new PetName(line);
|
||||
String val = pn.toString();
|
||||
System.out.println("OK? " + val.equals(line) + ": " + line + " [" + val + "]");
|
||||
}
|
||||
}
|
74
apps/syndie/java/src/net/i2p/syndie/PetNameDB.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class PetNameDB {
|
||||
/** name (String) to PetName mapping */
|
||||
private Map _names;
|
||||
|
||||
public PetNameDB() {
|
||||
_names = Collections.synchronizedMap(new HashMap());
|
||||
}
|
||||
|
||||
public PetName get(String name) { return (PetName)_names.get(name); }
|
||||
public boolean exists(String name) { return _names.containsKey(name); }
|
||||
public void set(String name, PetName pn) { _names.put(name, pn); }
|
||||
public void remove(String name) { _names.remove(name); }
|
||||
public Set getNames() { return new HashSet(_names.keySet()); }
|
||||
public List getGroups() {
|
||||
List rv = new ArrayList();
|
||||
for (Iterator iter = new HashSet(_names.values()).iterator(); iter.hasNext(); ) {
|
||||
PetName name = (PetName)iter.next();
|
||||
for (int i = 0; i < name.getGroupCount(); i++)
|
||||
if (!rv.contains(name.getGroup(i)))
|
||||
rv.add(name.getGroup(i));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public String getNameByLocation(String location) {
|
||||
if (location == null) return null;
|
||||
synchronized (_names) {
|
||||
for (Iterator iter = _names.values().iterator(); iter.hasNext(); ) {
|
||||
PetName name = (PetName)iter.next();
|
||||
if ( (name.getLocation() != null) && (name.getLocation().trim().equals(location.trim())) )
|
||||
return name.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void load(String location) throws IOException {
|
||||
File f = new File(location);
|
||||
if (!f.exists()) return;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
PetName name = new PetName(line);
|
||||
if (name.getName() != null)
|
||||
_names.put(name.getName(), name);
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
public void store(String location) throws IOException {
|
||||
Writer out = null;
|
||||
try {
|
||||
out = new OutputStreamWriter(new FileOutputStream(location), "UTF-8");
|
||||
for (Iterator names = getNames().iterator(); names.hasNext(); ) {
|
||||
PetName name = get((String)names.next());
|
||||
if (name != null)
|
||||
out.write(name.toString() + "\n");
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
package net.i2p.syndie;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
@@ -24,9 +26,18 @@ public class User {
|
||||
private String _addressbookLocation;
|
||||
private boolean _showImagesByDefault;
|
||||
private boolean _showExpandedByDefault;
|
||||
private String _defaultSelector;
|
||||
private long _lastLogin;
|
||||
private long _lastMetaEntry;
|
||||
private boolean _allowAccessRemote;
|
||||
private boolean _authenticated;
|
||||
private String _eepProxyHost;
|
||||
private int _eepProxyPort;
|
||||
private String _webProxyHost;
|
||||
private int _webProxyPort;
|
||||
private String _torProxyHost;
|
||||
private int _torProxyPort;
|
||||
private PetNameDB _petnames;
|
||||
|
||||
public User() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
@@ -40,11 +51,20 @@ public class User {
|
||||
_mostRecentEntry = -1;
|
||||
_blogGroups = new HashMap();
|
||||
_shitlistedBlogs = new ArrayList();
|
||||
_defaultSelector = null;
|
||||
_addressbookLocation = "userhosts.txt";
|
||||
_showImagesByDefault = false;
|
||||
_showImagesByDefault = true;
|
||||
_showExpandedByDefault = false;
|
||||
_allowAccessRemote = false;
|
||||
_eepProxyHost = null;
|
||||
_webProxyHost = null;
|
||||
_torProxyHost = null;
|
||||
_eepProxyPort = -1;
|
||||
_webProxyPort = -1;
|
||||
_torProxyPort = -1;
|
||||
_lastLogin = -1;
|
||||
_lastMetaEntry = 0;
|
||||
_petnames = new PetNameDB();
|
||||
}
|
||||
|
||||
public boolean getAuthenticated() { return _authenticated; }
|
||||
@@ -60,21 +80,35 @@ public class User {
|
||||
public long getLastLogin() { return _lastLogin; }
|
||||
public String getHashedPassword() { return _hashedPassword; }
|
||||
public long getLastMetaEntry() { return _lastMetaEntry; }
|
||||
public String getDefaultSelector() { return _defaultSelector; }
|
||||
public void setDefaultSelector(String sel) { _defaultSelector = sel; }
|
||||
public boolean getAllowAccessRemote() { return _allowAccessRemote; }
|
||||
public void setAllowAccessRemote(boolean allow) { _allowAccessRemote = true; }
|
||||
|
||||
public void setMostRecentEntry(long id) { _mostRecentEntry = id; }
|
||||
public void setLastMetaEntry(long id) { _lastMetaEntry = id; }
|
||||
|
||||
public String getEepProxyHost() { return _eepProxyHost; }
|
||||
public int getEepProxyPort() { return _eepProxyPort; }
|
||||
public String getWebProxyHost() { return _webProxyHost; }
|
||||
public int getWebProxyPort() { return _webProxyPort; }
|
||||
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();
|
||||
}
|
||||
|
||||
public String login(String login, String pass, Properties props) {
|
||||
String expectedPass = props.getProperty("password");
|
||||
String hpass = Base64.encode(_context.sha().calculateHash(pass.getBytes()).getData());
|
||||
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;
|
||||
@@ -128,18 +162,82 @@ 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"));
|
||||
|
||||
_defaultSelector = props.getProperty("defaultselector");
|
||||
String allow = props.getProperty("allowaccessremote", "false");
|
||||
_allowAccessRemote = (allow != null) && (allow.equals("true"));
|
||||
_eepProxyPort = getInt(props.getProperty("eepproxyport"));
|
||||
_webProxyPort = getInt(props.getProperty("webproxyport"));
|
||||
_torProxyPort = getInt(props.getProperty("torproxyport"));
|
||||
_eepProxyHost = props.getProperty("eepproxyhost");
|
||||
_webProxyHost = props.getProperty("webproxyhost");
|
||||
_torProxyHost = props.getProperty("torproxyhost");
|
||||
_lastLogin = _context.clock().now();
|
||||
_authenticated = true;
|
||||
return LOGIN_OK;
|
||||
}
|
||||
|
||||
public static final String LOGIN_OK = "Logged in";
|
||||
private int getInt(String val) {
|
||||
if (val == null) return -1;
|
||||
try { return Integer.parseInt(val); } catch (NumberFormatException nfe) { return -1; }
|
||||
}
|
||||
|
||||
public static final String LOGIN_OK = "<span class=\"b_loginMsgOk\">Logged in</span>";
|
||||
|
||||
public String export() {
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
buf.append("password=" + getHashedPassword() + "\n");
|
||||
buf.append("blog=" + getBlog().toBase64() + "\n");
|
||||
buf.append("lastid=" + getMostRecentEntry() + "\n");
|
||||
buf.append("lastmetaedition=" + getLastMetaEntry() + "\n");
|
||||
buf.append("lastlogin=" + getLastLogin() + "\n");
|
||||
buf.append("addressbook=" + getAddressbookLocation() + "\n");
|
||||
buf.append("showimages=" + getShowImages() + "\n");
|
||||
buf.append("showexpanded=" + getShowExpanded() + "\n");
|
||||
buf.append("defaultselector=" + getDefaultSelector() + "\n");
|
||||
buf.append("allowaccessremote=" + _allowAccessRemote + "\n");
|
||||
|
||||
buf.append("groups=");
|
||||
Map groups = getBlogGroups();
|
||||
for (Iterator iter = groups.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
List selectors = (List)groups.get(name);
|
||||
buf.append(name).append(':');
|
||||
for (int i = 0; i < selectors.size(); i++) {
|
||||
buf.append(selectors.get(i));
|
||||
if (i + 1 < selectors.size())
|
||||
buf.append(",");
|
||||
}
|
||||
if (iter.hasNext())
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append('\n');
|
||||
// shitlist=hash,hash,hash
|
||||
List shitlistedBlogs = getShitlistedBlogs();
|
||||
if (shitlistedBlogs.size() > 0) {
|
||||
buf.setLength(0);
|
||||
buf.append("shitlistedblogs=");
|
||||
for (int i = 0; i < shitlistedBlogs.size(); i++) {
|
||||
Hash blog = (Hash)shitlistedBlogs.get(i);
|
||||
buf.append(blog.toBase64());
|
||||
if (i + 1 < shitlistedBlogs.size())
|
||||
buf.append(',');
|
||||
}
|
||||
buf.append('\n');
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
@@ -26,16 +29,24 @@ public class ArchiveIndex {
|
||||
protected List _newestBlogs;
|
||||
/** list of BlogURI objects */
|
||||
protected List _newestEntries;
|
||||
/** parent message to a set of replies, ordered with the oldest first */
|
||||
protected Map _replies;
|
||||
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();
|
||||
_headers = new Properties();
|
||||
_replies = Collections.synchronizedMap(new HashMap());
|
||||
_generatedOn = -1;
|
||||
if (shouldLoad)
|
||||
setIsLocal("true");
|
||||
@@ -77,6 +88,58 @@ public class ArchiveIndex {
|
||||
/** get the raw entry size (including attachments) from the given blog/tag pair */
|
||||
public long getBlogEntrySizeKB(int index, int entryIndex) { return ((EntrySummary)((BlogSummary)_blogs.get(index)).entries.get(entryIndex)).size; }
|
||||
|
||||
public boolean getEntryIsKnown(BlogURI uri) { return getEntry(uri) != null; }
|
||||
public long getBlogEntrySizeKB(BlogURI uri) {
|
||||
EntrySummary entry = getEntry(uri);
|
||||
if (entry == null) return -1;
|
||||
return entry.size;
|
||||
}
|
||||
private EntrySummary getEntry(BlogURI uri) {
|
||||
if ( (uri == null) || (uri.getKeyHash() == null) || (uri.getEntryId() < 0) ) return null;
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
BlogSummary summary = (BlogSummary)_blogs.get(i);
|
||||
if (summary.blog.equals(uri.getKeyHash())) {
|
||||
for (int j = 0; j < summary.entries.size(); j++) {
|
||||
EntrySummary entry = (EntrySummary)summary.entries.get(j);
|
||||
if (entry.entry.equals(uri))
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Set getBlogEntryTags(BlogURI uri) {
|
||||
Set tags = new HashSet();
|
||||
if ( (uri == null) || (uri.getKeyHash() == null) || (uri.getEntryId() < 0) ) return tags;
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
BlogSummary summary = (BlogSummary)_blogs.get(i);
|
||||
if (summary.blog.equals(uri.getKeyHash())) {
|
||||
for (int j = 0; j < summary.entries.size(); j++) {
|
||||
EntrySummary entry = (EntrySummary)summary.entries.get(j);
|
||||
if (entry.entry.equals(uri)) {
|
||||
tags.add(summary.tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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(); }
|
||||
public Hash getNewestBlog(int index) { return (Hash)_newestBlogs.get(index); }
|
||||
@@ -100,7 +163,13 @@ public class ArchiveIndex {
|
||||
rv.add(getBlog(i));
|
||||
return rv;
|
||||
}
|
||||
|
||||
public List getReplies(BlogURI uri) {
|
||||
Set replies = (Set)_replies.get(uri);
|
||||
if (replies == null) return Collections.EMPTY_LIST;
|
||||
synchronized (replies) {
|
||||
return new ArrayList(replies);
|
||||
}
|
||||
}
|
||||
public void setLocation(String location) {
|
||||
try {
|
||||
File l = new File(location);
|
||||
@@ -143,7 +212,7 @@ public class ArchiveIndex {
|
||||
_newestBlogs = new ArrayList();
|
||||
_newestEntries = new ArrayList();
|
||||
_headers = new Properties();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(index));
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(index, "UTF-8"));
|
||||
String line = null;
|
||||
line = in.readLine();
|
||||
if (line == null)
|
||||
@@ -193,8 +262,8 @@ public class ArchiveIndex {
|
||||
_newestBlogs = parseNewestBlogs(val);
|
||||
else if (key.equals("NewestEntries"))
|
||||
_newestEntries = parseNewestEntries(val);
|
||||
else
|
||||
System.err.println("Key: " + key + " val: " + val);
|
||||
//else
|
||||
// System.err.println("Key: " + key + " val: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,14 +286,31 @@ public class ArchiveIndex {
|
||||
}
|
||||
if (tag != null) {
|
||||
if (!tag.equals(summary.tag)) {
|
||||
System.out.println("Tag [" + summary.tag + "] does not match the requested [" + tag + "]");
|
||||
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++) {
|
||||
b.append((int)tag.charAt(j));
|
||||
b.append('.');
|
||||
if (summary.tag.length() > j+1)
|
||||
b.append((int)summary.tag.charAt(j));
|
||||
else
|
||||
b.append('_');
|
||||
b.append(' ');
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("tag.summary: " + b.toString());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < summary.entries.size(); j++) {
|
||||
EntrySummary entry = (EntrySummary)summary.entries.get(j);
|
||||
ordered.put(new Long(0-entry.entry.getEntryId()), entry.entry);
|
||||
String k = (Long.MAX_VALUE-entry.entry.getEntryId()) + "-" + entry.entry.getKeyHash().toBase64();
|
||||
ordered.put(k, entry.entry);
|
||||
//System.err.println("Including match: " + k);
|
||||
}
|
||||
}
|
||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) {
|
||||
@@ -264,8 +350,10 @@ public class ArchiveIndex {
|
||||
if (tok.countTokens() < 4)
|
||||
return;
|
||||
tok.nextToken();
|
||||
Hash keyHash = new Hash(Base64.decode(tok.nextToken()));
|
||||
long when = getIndexDate(tok.nextToken());
|
||||
String keyStr = tok.nextToken();
|
||||
Hash keyHash = new Hash(Base64.decode(keyStr));
|
||||
String whenStr = tok.nextToken();
|
||||
long when = getIndexDate(whenStr);
|
||||
String tag = tok.nextToken();
|
||||
BlogSummary summary = new BlogSummary();
|
||||
summary.blog = keyHash;
|
||||
@@ -281,7 +369,7 @@ public class ArchiveIndex {
|
||||
_blogs.add(summary);
|
||||
}
|
||||
|
||||
private SimpleDateFormat _dateFmt = new SimpleDateFormat("yyyyMMdd");
|
||||
private SimpleDateFormat _dateFmt = new SimpleDateFormat("yyyyMMdd", Locale.UK);
|
||||
private long getIndexDate(String yyyymmdd) {
|
||||
synchronized (_dateFmt) {
|
||||
try {
|
||||
@@ -315,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 */
|
||||
|
@@ -2,6 +2,7 @@ package net.i2p.syndie.data;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -85,7 +86,7 @@ public class Attachment {
|
||||
for (int i = 0; i < _keys.size(); i++) {
|
||||
meta.append(_keys.get(i)).append(':').append(_values.get(i)).append('\n');
|
||||
}
|
||||
_rawMetadata = meta.toString().getBytes();
|
||||
_rawMetadata = DataHelper.getUTF8(meta);
|
||||
}
|
||||
|
||||
private void parseMeta() {
|
||||
@@ -96,10 +97,10 @@ public class Attachment {
|
||||
int valBegin = -1;
|
||||
for (int i = 0; i < _rawMetadata.length; i++) {
|
||||
if (_rawMetadata[i] == ':') {
|
||||
key = new String(_rawMetadata, keyBegin, i - keyBegin);
|
||||
key = DataHelper.getUTF8(_rawMetadata, keyBegin, i - keyBegin);
|
||||
valBegin = i + 1;
|
||||
} else if (_rawMetadata[i] == '\n') {
|
||||
val = new String(_rawMetadata, valBegin, i - valBegin);
|
||||
val = DataHelper.getUTF8(_rawMetadata, valBegin, i - valBegin);
|
||||
_keys.add(key);
|
||||
_values.add(val);
|
||||
keyBegin = i + 1;
|
||||
|
@@ -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>
|
||||
@@ -13,6 +14,7 @@ import net.i2p.I2PAppContext;
|
||||
* Required keys:
|
||||
* Owner: base64 of their signing public key
|
||||
* Signature: base64 of the DSA signature of the rest of the ordered metadata
|
||||
* Edition: base10 unique identifier for this metadata (higher clobbers lower)
|
||||
*
|
||||
* Optional keys:
|
||||
* Posters: comma delimited list of base64 signing public keys that
|
||||
@@ -53,18 +55,27 @@ public class BlogInfo {
|
||||
public static final String SIGNATURE = "Signature";
|
||||
public static final String NAME = "Name";
|
||||
public static final String DESCRIPTION = "Description";
|
||||
public static final String EDITION = "Edition";
|
||||
|
||||
public void load(InputStream in) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
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) {
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("Read info line [" + line + "]");
|
||||
line = line.trim();
|
||||
int len = line.length();
|
||||
int split = line.indexOf(':');
|
||||
if ( (len <= 0) || (split <= 0) || (split >= len - 2) )
|
||||
if ( (len <= 0) || (split <= 0) ) {
|
||||
continue;
|
||||
} else if (split >= len - 1) {
|
||||
names.add(line.substring(0, split).trim());
|
||||
vals.add("");
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = line.substring(0, split).trim();
|
||||
String val = line.substring(split+1).trim();
|
||||
@@ -76,6 +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] + "]");
|
||||
}
|
||||
|
||||
String keyStr = getProperty(OWNER_KEY);
|
||||
@@ -102,13 +114,22 @@ public class BlogInfo {
|
||||
if ( (includeRealSignature) || (!SIGNATURE.equals(_optionNames[i])) )
|
||||
buf.append(_optionNames[i]).append(':').append(_optionValues[i]).append('\n');
|
||||
}
|
||||
out.write(buf.toString().getBytes());
|
||||
String s = buf.toString();
|
||||
out.write(s.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
public String getProperty(String name) {
|
||||
for (int i = 0; i < _optionNames.length; i++) {
|
||||
if (_optionNames[i].equals(name))
|
||||
return _optionValues[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);
|
||||
//}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -133,6 +154,18 @@ public class BlogInfo {
|
||||
_optionValues = values;
|
||||
}
|
||||
|
||||
public int getEdition() {
|
||||
String e = getProperty(EDITION);
|
||||
if (e != null) {
|
||||
try {
|
||||
return Integer.parseInt(e);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String[] getProperties() { return _optionNames; }
|
||||
|
||||
public SigningPublicKey[] getPosters() { return _posters; }
|
||||
@@ -151,7 +184,9 @@ public class BlogInfo {
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(512);
|
||||
write(out, false);
|
||||
return ctx.dsa().verifySignature(_signature, out.toByteArray(), _key);
|
||||
out.close();
|
||||
byte data[] = out.toByteArray();
|
||||
return ctx.dsa().verifySignature(_signature, data, _key);
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
@@ -192,4 +227,54 @@ public class BlogInfo {
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final String TEST_STRING = "\u20AC\u00DF\u6771\u10400\u00F6";
|
||||
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
if (true) {
|
||||
try {
|
||||
Object keys[] = ctx.keyGenerator().generateSigningKeypair();
|
||||
SigningPublicKey pub = (SigningPublicKey)keys[0];
|
||||
SigningPrivateKey priv = (SigningPrivateKey)keys[1];
|
||||
|
||||
Properties opts = new Properties();
|
||||
opts.setProperty("Name", TEST_STRING);
|
||||
opts.setProperty("Description", TEST_STRING);
|
||||
opts.setProperty("Edition", "0");
|
||||
opts.setProperty("ContactURL", TEST_STRING);
|
||||
|
||||
String nameOrig = opts.getProperty("Name");
|
||||
BlogInfo info = new BlogInfo(pub, null, opts);
|
||||
info.sign(ctx, priv);
|
||||
boolean ok = info.verify(ctx);
|
||||
System.err.println("sign&verify: " + ok);
|
||||
|
||||
FileOutputStream o = new FileOutputStream("bloginfo-test.dat");
|
||||
info.write(o, true);
|
||||
o.close();
|
||||
FileInputStream i = new FileInputStream("bloginfo-test.dat");
|
||||
byte buf[] = new byte[4096];
|
||||
int sz = DataHelper.read(i, buf);
|
||||
BlogInfo read = new BlogInfo();
|
||||
read.load(new ByteArrayInputStream(buf, 0, sz));
|
||||
ok = read.verify(ctx);
|
||||
System.err.println("write to disk, verify read: " + ok);
|
||||
System.err.println("Data: " + Base64.encode(buf, 0, sz));
|
||||
System.err.println("Str : " + new String(buf, 0, sz));
|
||||
|
||||
System.err.println("Name ok? " + read.getProperty("Name").equals(TEST_STRING));
|
||||
System.err.println("Desc ok? " + read.getProperty("Description").equals(TEST_STRING));
|
||||
System.err.println("Name ok? " + read.getProperty("ContactURL").equals(TEST_STRING));
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
} else {
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(args[0]);
|
||||
BlogInfo info = new BlogInfo();
|
||||
info.load(in);
|
||||
boolean ok = info.verify(I2PAppContext.getGlobalContext());
|
||||
System.out.println("OK? " + ok + " :" + info);
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,19 @@ public class BlogURI {
|
||||
_entryId = -1;
|
||||
}
|
||||
}
|
||||
} else if (uri.startsWith("entry://")) {
|
||||
int off = "entry://".length();
|
||||
_blogHash = new Hash(Base64.decode(uri.substring(off, off+44))); // 44 chars == base64(32 bytes)
|
||||
int entryStart = uri.indexOf('/', off+1);
|
||||
if (entryStart < 0) {
|
||||
_entryId = -1;
|
||||
} else {
|
||||
try {
|
||||
_entryId = Long.parseLong(uri.substring(entryStart+1).trim());
|
||||
} catch (NumberFormatException nfe) {
|
||||
_entryId = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_blogHash = null;
|
||||
_entryId = -1;
|
||||
@@ -61,7 +74,10 @@ public class BlogURI {
|
||||
DataHelper.eq(_blogHash, ((BlogURI)obj)._blogHash);
|
||||
}
|
||||
public int hashCode() {
|
||||
return (int)_entryId;
|
||||
int rv = (int)_entryId;
|
||||
if (_blogHash != null)
|
||||
rv += _blogHash.hashCode();
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
@@ -69,6 +85,8 @@ public class BlogURI {
|
||||
test("blog://Vq~AlW-r7OM763okVUFIDvVFzxOjpNNsAx0rFb2yaE8=");
|
||||
test("blog://Vq~AlW-r7OM763okVUFIDvVFzxOjpNNsAx0rFb2yaE8=/");
|
||||
test("blog://Vq~AlW-r7OM763okVUFIDvVFzxOjpNNsAx0rFb2yaE8=/123456789");
|
||||
test("entry://Vq~AlW-r7OM763okVUFIDvVFzxOjpNNsAx0rFb2yaE8=/");
|
||||
test("entry://Vq~AlW-r7OM763okVUFIDvVFzxOjpNNsAx0rFb2yaE8=/123456789");
|
||||
}
|
||||
private static void test(String uri) {
|
||||
BlogURI u = new BlogURI(uri);
|
||||
|
@@ -0,0 +1,86 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
/**
|
||||
* Create a new blog metadata & set of entries using some crazy UTF8 encoded chars,
|
||||
* then make sure they're always valid. These blogs & entries can then be fed into
|
||||
* jetty/syndie/etc to see how and where they are getting b0rked.
|
||||
*/
|
||||
public class EncodingTestGenerator {
|
||||
public EncodingTestGenerator() {}
|
||||
public static final String TEST_STRING = "\u20AC\u00DF\u6771\u10400\u00F6";
|
||||
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
try {
|
||||
Object keys[] = ctx.keyGenerator().generateSigningKeypair();
|
||||
SigningPublicKey pub = (SigningPublicKey)keys[0];
|
||||
SigningPrivateKey priv = (SigningPrivateKey)keys[1];
|
||||
|
||||
Properties opts = new Properties();
|
||||
opts.setProperty("Name", TEST_STRING);
|
||||
opts.setProperty("Description", TEST_STRING);
|
||||
opts.setProperty("Edition", "0");
|
||||
opts.setProperty("ContactURL", TEST_STRING);
|
||||
|
||||
String nameOrig = opts.getProperty("Name");
|
||||
BlogInfo info = new BlogInfo(pub, null, opts);
|
||||
info.sign(ctx, priv);
|
||||
boolean ok = info.verify(ctx);
|
||||
System.err.println("sign&verify: " + ok);
|
||||
|
||||
FileOutputStream o = new FileOutputStream("encodedMeta.dat");
|
||||
info.write(o, true);
|
||||
o.close();
|
||||
FileInputStream i = new FileInputStream("encodedMeta.dat");
|
||||
byte buf[] = new byte[4096];
|
||||
int sz = DataHelper.read(i, buf);
|
||||
BlogInfo read = new BlogInfo();
|
||||
read.load(new ByteArrayInputStream(buf, 0, sz));
|
||||
ok = read.verify(ctx);
|
||||
System.err.println("write to disk, verify read: " + ok);
|
||||
System.err.println("Name ok? " + read.getProperty("Name").equals(TEST_STRING));
|
||||
System.err.println("Desc ok? " + read.getProperty("Description").equals(TEST_STRING));
|
||||
System.err.println("Name ok? " + read.getProperty("ContactURL").equals(TEST_STRING));
|
||||
|
||||
// ok now lets create some entries
|
||||
BlogURI uri = new BlogURI(read.getKey().calculateHash(), 0);
|
||||
String tags[] = new String[4];
|
||||
for (int j = 0; j < tags.length; j++)
|
||||
tags[j] = TEST_STRING + "_" + j;
|
||||
StringBuffer smlOrig = new StringBuffer(512);
|
||||
smlOrig.append("Subject: ").append(TEST_STRING).append("\n\n");
|
||||
smlOrig.append("Hi with ").append(TEST_STRING);
|
||||
EntryContainer container = new EntryContainer(uri, tags, DataHelper.getUTF8(smlOrig));
|
||||
container.seal(ctx, priv, null);
|
||||
ok = container.verifySignature(ctx, read);
|
||||
System.err.println("Sealed and verified entry: " + ok);
|
||||
FileOutputStream fos = new FileOutputStream("encodedEntry.dat");
|
||||
container.write(fos, true);
|
||||
fos.close();
|
||||
System.out.println("Written to " + new File("encodedEntry.dat").getAbsolutePath());
|
||||
|
||||
FileInputStream fis = new FileInputStream("encodedEntry.dat");
|
||||
EntryContainer read2 = new EntryContainer();
|
||||
read2.load(fis);
|
||||
ok = read2.verifySignature(ctx, read);
|
||||
System.out.println("Read ok? " + ok);
|
||||
|
||||
read2.parseRawData(ctx);
|
||||
String tagsRead[] = read2.getTags();
|
||||
for (int j = 0; j < tagsRead.length; j++) {
|
||||
if (!tags[j].equals(tagsRead[j]))
|
||||
System.err.println("Tag error [" + j + "]: read = [" + tagsRead[j] + "] want [" + tags[j] + "]");
|
||||
else
|
||||
System.err.println("Tag ok [" + j + "]");
|
||||
}
|
||||
String readText = read2.getEntry().getText();
|
||||
ok = readText.equals(smlOrig.toString());
|
||||
System.err.println("SML text ok? " + ok);
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
@@ -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>
|
||||
@@ -58,7 +59,7 @@ public class EntryContainer {
|
||||
public EntryContainer(BlogURI uri, String tags[], byte smlData[]) {
|
||||
this();
|
||||
_entryURI = uri;
|
||||
_entryData = new Entry(new String(smlData));
|
||||
_entryData = new Entry(DataHelper.getUTF8(smlData));
|
||||
setHeader(HEADER_BLOGKEY, Base64.encode(uri.getKeyHash().getData()));
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; tags != null && i < tags.length; i++)
|
||||
@@ -71,8 +72,35 @@ public class EntryContainer {
|
||||
|
||||
public int getFormat() { return _format; }
|
||||
|
||||
private String readLine(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
|
||||
int i = 0;
|
||||
while (true) {
|
||||
int c = in.read();
|
||||
if ( (c == (int)'\n') || (c == (int)'\r') ) {
|
||||
break;
|
||||
} else if (c == -1) {
|
||||
if (i == 0)
|
||||
return null;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
baos.write(c);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return DataHelper.getUTF8(baos.toByteArray());
|
||||
//BufferedReader r = new BufferedReader(new InputStreamReader(in, "UTF-8"), 1);
|
||||
//String line = r.readLine();
|
||||
//return line;
|
||||
}
|
||||
|
||||
public void load(InputStream source) throws IOException {
|
||||
String fmt = DataHelper.readLine(source).trim();
|
||||
String line = readLine(source);
|
||||
if (line == null) throw new IOException("No format line in the entry");
|
||||
//System.err.println("read container format line [" + line + "]");
|
||||
String fmt = line.trim();
|
||||
if (FORMAT_ZIP_UNENCRYPTED_STR.equals(fmt)) {
|
||||
_format = FORMAT_ZIP_UNENCRYPTED;
|
||||
} else if (FORMAT_ZIP_ENCRYPTED_STR.equals(fmt)) {
|
||||
@@ -81,35 +109,51 @@ public class EntryContainer {
|
||||
throw new IOException("Unsupported entry format: " + fmt);
|
||||
}
|
||||
|
||||
String line = null;
|
||||
while ( (line = DataHelper.readLine(source)) != null) {
|
||||
while ( (line = readLine(source)) != null) {
|
||||
//System.err.println("read container header line [" + line + "]");
|
||||
line = line.trim();
|
||||
int len = line.length();
|
||||
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();
|
||||
|
||||
String sigStr = DataHelper.readLine(source);
|
||||
String sigStr = readLine(source);
|
||||
//System.err.println("read container signature line [" + line + "]");
|
||||
if ( (sigStr == null) || (sigStr.indexOf("Signature:") == -1) )
|
||||
throw new IOException("No signature line");
|
||||
sigStr = sigStr.substring("Signature:".length()+1).trim();
|
||||
|
||||
_signature = new Signature(Base64.decode(sigStr));
|
||||
//System.out.println("Sig: " + _signature.toBase64());
|
||||
|
||||
line = DataHelper.readLine(source).trim();
|
||||
line = readLine(source);
|
||||
//System.err.println("read container size line [" + line + "]");
|
||||
if (line == null)
|
||||
throw new IOException("No size line");
|
||||
line = line.trim();
|
||||
int dataSize = -1;
|
||||
try {
|
||||
int index = line.indexOf("Size:");
|
||||
if (index == 0)
|
||||
dataSize = Integer.parseInt(line.substring("Size:".length()+1).trim());
|
||||
else
|
||||
throw new IOException("Invalid size line");
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IOException("Invalid entry size: " + line);
|
||||
}
|
||||
@@ -123,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
|
||||
@@ -157,7 +203,7 @@ public class EntryContainer {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream out = new ZipOutputStream(baos);
|
||||
ZipEntry ze = new ZipEntry(ZIP_ENTRY);
|
||||
byte data[] = _entryData.getText().getBytes();
|
||||
byte data[] = DataHelper.getUTF8(_entryData.getText());
|
||||
ze.setTime(0);
|
||||
out.putNextEntry(ze);
|
||||
out.write(data);
|
||||
@@ -214,7 +260,7 @@ public class EntryContainer {
|
||||
|
||||
String name = entry.getName();
|
||||
if (ZIP_ENTRY.equals(name)) {
|
||||
_entryData = new Entry(new String(entryData));
|
||||
_entryData = new Entry(DataHelper.getUTF8(entryData));
|
||||
} else if (name.startsWith(ZIP_ATTACHMENT_PREFIX)) {
|
||||
attachments.put(name, (Object)entryData);
|
||||
} else if (name.startsWith(ZIP_ATTACHMENT_META_PREFIX)) {
|
||||
@@ -229,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) ) {
|
||||
@@ -303,8 +353,9 @@ public class EntryContainer {
|
||||
String keyHash = getHeader(HEADER_BLOGKEY);
|
||||
String idVal = getHeader(HEADER_ENTRYID);
|
||||
|
||||
if (keyHash == null)
|
||||
if (keyHash == null) {
|
||||
throw new IOException("Missing " + HEADER_BLOGKEY + " header");
|
||||
}
|
||||
|
||||
long entryId = -1;
|
||||
if ( (idVal != null) && (idVal.length() > 0) ) {
|
||||
@@ -377,7 +428,7 @@ public class EntryContainer {
|
||||
String str = buf.toString();
|
||||
|
||||
//System.out.println("Writing raw: \n[" + str + "] / " + I2PAppContext.getGlobalContext().sha().calculateHash(str.getBytes()) + ", raw data: " + I2PAppContext.getGlobalContext().sha().calculateHash(_rawData).toBase64() + "\n");
|
||||
out.write(str.getBytes());
|
||||
out.write(DataHelper.getUTF8(str));
|
||||
out.write(_rawData);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
@@ -67,4 +71,36 @@ public class LocalArchiveIndex extends ArchiveIndex {
|
||||
if (!_newestEntries.contains(entry))
|
||||
_newestEntries.add(entry);
|
||||
}
|
||||
|
||||
public void addReply(BlogURI parent, BlogURI reply) {
|
||||
Set replies = (Set)_replies.get(parent);
|
||||
if (replies == null) {
|
||||
replies = Collections.synchronizedSet(new TreeSet(BlogURIComparator.HIGHEST_ID_FIRST));
|
||||
_replies.put(parent, replies);
|
||||
}
|
||||
replies.add(reply);
|
||||
//System.err.println("Adding reply to " + parent + " from child " + reply + " (# replies: " + replies.size() + ")");
|
||||
}
|
||||
|
||||
private static class BlogURIComparator implements Comparator {
|
||||
public static final BlogURIComparator HIGHEST_ID_FIRST = new BlogURIComparator(true);
|
||||
public static final BlogURIComparator HIGHEST_ID_LAST = new BlogURIComparator(false);
|
||||
private boolean _highestFirst;
|
||||
public BlogURIComparator(boolean highestFirst) {
|
||||
_highestFirst = highestFirst;
|
||||
}
|
||||
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
if ( (lhs == null) || !(lhs instanceof BlogURI) ) return 1;
|
||||
if ( (rhs == null) || !(rhs instanceof BlogURI) ) return -1;
|
||||
BlogURI l = (BlogURI)lhs;
|
||||
BlogURI r = (BlogURI)rhs;
|
||||
if (l.getEntryId() > r.getEntryId())
|
||||
return (_highestFirst ? 1 : -1);
|
||||
else if (l.getEntryId() < r.getEntryId())
|
||||
return (_highestFirst ? -1 : 1);
|
||||
else
|
||||
return DataHelper.compareTo(l.getKeyHash().getData(), r.getKeyHash().getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,81 @@
|
||||
package net.i2p.syndie.data;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.Archive;
|
||||
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(I2PAppContext.getGlobalContext(), false); }
|
||||
|
||||
private static ArchiveIndex index() { return BlogManager.instance().getArchive().getIndex(); }
|
||||
|
||||
public String getVersion() { return index().getVersion(); }
|
||||
public Properties getHeaders() { return index().getHeaders(); }
|
||||
public int getAllBlogs() { return index().getAllBlogs(); }
|
||||
public int getNewBlogs() { return index().getNewBlogs(); }
|
||||
public int getAllEntries() { return index().getAllEntries(); }
|
||||
public int getNewEntries() { return index().getNewEntries(); }
|
||||
public long getTotalSize() { return index().getTotalSize(); }
|
||||
public long getNewSize() { return index().getNewSize(); }
|
||||
public long getGeneratedOn() { return index().getGeneratedOn(); }
|
||||
|
||||
public String getNewSizeStr() { return index().getNewSizeStr(); }
|
||||
public String getTotalSizeStr() { return index().getTotalSizeStr(); }
|
||||
|
||||
/** how many blogs/tags are indexed */
|
||||
public int getIndexBlogs() { return index().getIndexBlogs(); }
|
||||
/** get the blog used for the given blog/tag pair */
|
||||
public Hash getBlog(int index) { return index().getBlog(index); }
|
||||
/** get the tag used for the given blog/tag pair */
|
||||
public String getBlogTag(int index) { return index().getBlogTag(index); }
|
||||
/** get the highest entry ID for the given blog/tag pair */
|
||||
public long getBlogLastUpdated(int index) { return index().getBlogLastUpdated(index); }
|
||||
/** get the entry count for the given blog/tag pair */
|
||||
public int getBlogEntryCount(int index) { return index().getBlogEntryCount(index); }
|
||||
/** get the entry from the given blog/tag pair */
|
||||
public BlogURI getBlogEntry(int index, int entryIndex) { return index().getBlogEntry(index, entryIndex); }
|
||||
/** get the raw entry size (including attachments) from the given blog/tag pair */
|
||||
public long getBlogEntrySizeKB(int index, int entryIndex) { return index().getBlogEntrySizeKB(index, entryIndex); }
|
||||
public boolean getEntryIsKnown(BlogURI uri) { return index().getEntryIsKnown(uri); }
|
||||
public long getBlogEntrySizeKB(BlogURI uri) { return index().getBlogEntrySizeKB(uri); }
|
||||
public Set getBlogEntryTags(BlogURI uri) { return index().getBlogEntryTags(uri); }
|
||||
/** how many 'new' blogs are listed */
|
||||
public int getNewestBlogCount() { return index().getNewestBlogCount(); }
|
||||
public Hash getNewestBlog(int index) { return index().getNewestBlog(index); }
|
||||
/** how many 'new' entries are listed */
|
||||
public int getNewestBlogEntryCount() { return index().getNewestBlogEntryCount(); }
|
||||
public BlogURI getNewestBlogEntry(int index) { return index().getNewestBlogEntry(index); }
|
||||
|
||||
/** list of locally known tags (String) under the given blog */
|
||||
public List getBlogTags(Hash blog) { return index().getBlogTags(blog); }
|
||||
/** list of unique blogs locally known (set of Hash) */
|
||||
public Set getUniqueBlogs() { return index().getUniqueBlogs(); }
|
||||
public void setLocation(String location) { return; }
|
||||
public void setIsLocal(String val) { return; }
|
||||
public void load(File location) throws IOException { return; }
|
||||
/** load up the index from an archive.txt */
|
||||
public void load(InputStream index) throws IOException { return; }
|
||||
|
||||
/**
|
||||
* Dig through the index for BlogURIs matching the given criteria, ordering the results by
|
||||
* their own entryIds.
|
||||
*
|
||||
* @param out where to store the matches
|
||||
* @param blog if set, what blog key must the entries be under
|
||||
* @param tag if set, what tag must the entry be in
|
||||
*
|
||||
*/
|
||||
public void selectMatchesOrderByEntryId(List out, Hash blog, String tag) {
|
||||
index().selectMatchesOrderByEntryId(out, blog, tag);
|
||||
}
|
||||
|
||||
/** export the index into an archive.txt */
|
||||
public String toString() { return index().toString(); }
|
||||
}
|
@@ -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) {}
|
||||
|
147
apps/syndie/java/src/net/i2p/syndie/sml/HTMLPreviewRenderer.java
Normal file
@@ -0,0 +1,147 @@
|
||||
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.*;
|
||||
import net.i2p.syndie.web.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class HTMLPreviewRenderer extends HTMLRenderer {
|
||||
private List _filenames;
|
||||
private List _fileTypes;
|
||||
private List _files;
|
||||
|
||||
public HTMLPreviewRenderer(I2PAppContext ctx, List filenames, List fileTypes, List files) {
|
||||
super(ctx);
|
||||
_filenames = filenames;
|
||||
_fileTypes = fileTypes;
|
||||
_files = files;
|
||||
}
|
||||
|
||||
protected String getAttachmentURLBase() { return "viewtempattachment.jsp"; }
|
||||
protected String getAttachmentURL(int id) {
|
||||
return getAttachmentURLBase() + "?" +
|
||||
ArchiveViewerBean.PARAM_ATTACHMENT + "=" + id;
|
||||
}
|
||||
|
||||
public void receiveAttachment(int id, String anchorText) {
|
||||
if (!continueBody()) { return; }
|
||||
if ( (id < 0) || (_files == null) || (id >= _files.size()) ) {
|
||||
_bodyBuffer.append(sanitizeString(anchorText));
|
||||
} else {
|
||||
File f = (File)_files.get(id);
|
||||
String name = (String)_filenames.get(id);
|
||||
String type = (String)_fileTypes.get(id);
|
||||
_bodyBuffer.append("<a ").append(getClass("attachmentView")).append(" href=\"").append(getAttachmentURL(id)).append("\">");
|
||||
_bodyBuffer.append(sanitizeString(anchorText)).append("</a>");
|
||||
_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 ").append(getClass("summDetail")).append(" >\n");
|
||||
_postBodyBuffer.append("<form action=\"").append(getAttachmentURLBase()).append("\">\n");
|
||||
_postBodyBuffer.append("<td colspan=\"2\" valign=\"top\" align=\"left\" ").append(getClass("summDetail")).append("> \n");
|
||||
|
||||
if (_files.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailAttachment")).append("Attachments:</span> ");
|
||||
_postBodyBuffer.append("<select ").append(getClass("summDetailAttachmentId")).append(" name=\"").append(ArchiveViewerBean.PARAM_ATTACHMENT).append("\">\n");
|
||||
for (int i = 0; i < _files.size(); i++) {
|
||||
_postBodyBuffer.append("<option value=\"").append(i).append("\">");
|
||||
File f = (File)_files.get(i);
|
||||
String name = (String)_filenames.get(i);
|
||||
String type = (String)_fileTypes.get(i);
|
||||
_postBodyBuffer.append(sanitizeString(name));
|
||||
_postBodyBuffer.append(" (").append(f.length()/1024).append("KB");
|
||||
_postBodyBuffer.append(", type ").append(sanitizeString(type)).append(")</option>\n");
|
||||
}
|
||||
_postBodyBuffer.append("</select>\n");
|
||||
_postBodyBuffer.append("<input ").append(getClass("summDetailAttachmentDl")).append(" type=\"submit\" value=\"Download\" name=\"Download\" /><br />\n");
|
||||
}
|
||||
|
||||
if (_blogs.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailBlog")).append("Blog references:</span> ");
|
||||
for (int i = 0; i < _blogs.size(); i++) {
|
||||
Blog b = (Blog)_blogs.get(i);
|
||||
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(getSpan("summDetailExternal")).append("External links:</span> ");
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
Link l = (Link)_links.get(i);
|
||||
_postBodyBuffer.append("<a ").append(getClass("summDetailExternalLink")).append(" href=\"externallink.jsp?");
|
||||
if (l.schema != null)
|
||||
_postBodyBuffer.append("schema=").append(sanitizeURL(l.schema)).append('&');
|
||||
if (l.location != null)
|
||||
_postBodyBuffer.append("location=").append(sanitizeURL(l.location)).append('&');
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(l.location));
|
||||
_postBodyBuffer.append(getSpan("summDetailExternalNet")).append(" (").append(sanitizeString(l.schema)).append(")</span></a> ");
|
||||
}
|
||||
_postBodyBuffer.append("<br />\n");
|
||||
}
|
||||
|
||||
if (_addresses.size() > 0) {
|
||||
_postBodyBuffer.append(getSpan("summDetailAddr")).append("Addresses:</span>");
|
||||
for (int i = 0; i < _addresses.size(); i++) {
|
||||
Address a = (Address)_addresses.get(i);
|
||||
|
||||
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(getSpan("summDetailArchive")).append("Archives:</span>");
|
||||
for (int i = 0; i < _archives.size(); i++) {
|
||||
ArchiveRef a = (ArchiveRef)_archives.get(i);
|
||||
_postBodyBuffer.append(" <a ").append(getClass("summDetailArchiveLink")).append(" href=\"").append(getArchiveURL(null, new SafeURL(a.locationSchema + "://" + a.location)));
|
||||
_postBodyBuffer.append("\">").append(sanitizeString(a.name)).append("</a>");
|
||||
if (a.description != null)
|
||||
_postBodyBuffer.append(": ").append(getSpan("summDetailArchiveDesc")).append(sanitizeString(a.description)).append("</span>");
|
||||
if (null == _user.getPetNameDB().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");
|
||||
}
|
||||
|
||||
_postBodyBuffer.append("</td>\n</form>\n</tr>\n");
|
||||
_postBodyBuffer.append("</table>\n");
|
||||
}
|
||||
}
|
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();
|
||||
@@ -196,6 +203,7 @@ public class SMLParser {
|
||||
private static final String T_HR = "hr";
|
||||
private static final String T_PRE = "pre";
|
||||
private static final String T_ATTACHMENT = "attachment";
|
||||
private static final String T_ARCHIVE = "archive";
|
||||
|
||||
private static final String P_ATTACHMENT = "attachment";
|
||||
private static final String P_WHO_QUOTED = "author";
|
||||
@@ -210,7 +218,13 @@ 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";
|
||||
private static final String P_ARCHIVE_LOCATION_SCHEMA = "schema";
|
||||
private static final String P_ARCHIVE_LOCATION = "location";
|
||||
private static final String P_ARCHIVE_POSTING_KEY = "postingkey";
|
||||
|
||||
private void parseTag(String tagName, Map attr, String body, EventReceiver receiver) {
|
||||
tagName = tagName.toLowerCase();
|
||||
@@ -241,10 +255,14 @@ public class SMLParser {
|
||||
}
|
||||
receiver.receiveBlog(getString(P_BLOG_NAME, attr), getString(P_BLOG_HASH, attr), getString(P_BLOG_TAG, attr),
|
||||
getLong(P_BLOG_ENTRY, attr), locations, body);
|
||||
} else if (T_ARCHIVE.equals(tagName)) {
|
||||
receiver.receiveArchive(getString(P_ARCHIVE_NAME, attr), getString(P_ARCHIVE_DESCRIPTION, attr),
|
||||
getString(P_ARCHIVE_LOCATION_SCHEMA, attr), getString(P_ARCHIVE_LOCATION, attr),
|
||||
getString(P_ARCHIVE_POSTING_KEY, attr), body);
|
||||
} 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)) {
|
||||
@@ -262,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 + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,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);
|
||||
@@ -426,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));
|
||||
}
|
||||
}
|
||||
|
186
apps/syndie/java/src/net/i2p/syndie/web/ArchiveServlet.java
Normal file
@@ -0,0 +1,186 @@
|
||||
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.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ArchiveServlet extends HttpServlet {
|
||||
|
||||
public void doGet(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")) {
|
||||
ExportServlet.export(req, resp);
|
||||
} else {
|
||||
String blog = getBlog(path);
|
||||
if (path.endsWith(Archive.METADATA_FILE)) {
|
||||
renderMetadata(blog, resp);
|
||||
} else if (path.endsWith(".snd")) {
|
||||
renderEntry(blog, getEntry(path), resp);
|
||||
} else {
|
||||
renderBlogIndex(blog, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getBlog(String path) {
|
||||
//System.err.println("Blog: [" + path + "]");
|
||||
int start = 0;
|
||||
int end = -1;
|
||||
int len = path.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (path.charAt(i) != '/') {
|
||||
start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int j = start + 1; j < len; j++) {
|
||||
if (path.charAt(j) == '/') {
|
||||
end = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end < 0) end = len;
|
||||
String rv = path.substring(start, end);
|
||||
//System.err.println("Blog: [" + path + "] rv: [" + rv + "]");
|
||||
return rv;
|
||||
}
|
||||
|
||||
private long getEntry(String path) {
|
||||
int start = path.lastIndexOf('/');
|
||||
if (start < 0) return -1;
|
||||
if (!(path.endsWith(".snd"))) return -1;
|
||||
String rv = path.substring(start+1, path.length()-".snd".length());
|
||||
//System.err.println("Entry: [" + path + "] rv: [" + rv + "]");
|
||||
try {
|
||||
return Long.parseLong(rv);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderRootIndex(HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/html;charset=utf-8");
|
||||
//resp.setCharacterEncoding("UTF-8");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
out.write(DataHelper.getUTF8("<a href=\"archive.txt\">archive.txt</a><br />\n"));
|
||||
ArchiveIndex index = BlogManager.instance().getArchive().getIndex();
|
||||
Set blogs = index.getUniqueBlogs();
|
||||
for (Iterator iter = blogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
String s = blog.toBase64();
|
||||
out.write(DataHelper.getUTF8("<a href=\"" + s + "/\">" + s + "</a><br />\n"));
|
||||
}
|
||||
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");
|
||||
resp.setHeader(HEADER_EXPORT_CAPABLE, "true");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
ArchiveIndex index = BlogManager.instance().getArchive().getIndex();
|
||||
out.write(DataHelper.getUTF8(index.toString()));
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void renderMetadata(String blog, HttpServletResponse resp) throws ServletException, IOException {
|
||||
byte b[] = Base64.decode(blog);
|
||||
if ( (b == null) || (b.length != Hash.HASH_LENGTH) ) {
|
||||
resp.sendError(404, "Invalid blog requested");
|
||||
return;
|
||||
}
|
||||
Hash h = new Hash(b);
|
||||
BlogInfo info = BlogManager.instance().getArchive().getBlogInfo(h);
|
||||
if (info == null) {
|
||||
resp.sendError(404, "Blog does not exist");
|
||||
return;
|
||||
}
|
||||
resp.setContentType("application/x-syndie-meta");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
info.write(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void renderBlogIndex(String blog, HttpServletResponse resp) throws ServletException, IOException {
|
||||
byte b[] = Base64.decode(blog);
|
||||
if ( (b == null) || (b.length != Hash.HASH_LENGTH) ) {
|
||||
resp.sendError(404, "Invalid blog requested");
|
||||
return;
|
||||
}
|
||||
Hash h = new Hash(b);
|
||||
|
||||
BlogInfo info = BlogManager.instance().getArchive().getBlogInfo(h);
|
||||
if (info == null) {
|
||||
resp.sendError(404, "Blog does not exist");
|
||||
return;
|
||||
}
|
||||
resp.setContentType("text/html;charset=utf-8");
|
||||
//resp.setCharacterEncoding("UTF-8");
|
||||
OutputStream out = resp.getOutputStream();
|
||||
out.write(DataHelper.getUTF8("<a href=\"..\">..</a><br />\n"));
|
||||
out.write(DataHelper.getUTF8("<a href=\"" + Archive.METADATA_FILE + "\">" + Archive.METADATA_FILE + "</a><br />\n"));
|
||||
List entries = new ArrayList(64);
|
||||
BlogManager.instance().getArchive().getIndex().selectMatchesOrderByEntryId(entries, h, null);
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI entry = (BlogURI)entries.get(i);
|
||||
out.write(DataHelper.getUTF8("<a href=\"" + entry.getEntryId() + ".snd\">" + entry.getEntryId() + ".snd</a><br />\n"));
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void renderEntry(String blog, long entryId, HttpServletResponse resp) throws ServletException, IOException {
|
||||
byte b[] = Base64.decode(blog);
|
||||
if ( (b == null) || (b.length != Hash.HASH_LENGTH) ) {
|
||||
resp.sendError(404, "Invalid blog requested");
|
||||
return;
|
||||
}
|
||||
Hash h = new Hash(b);
|
||||
BlogInfo info = BlogManager.instance().getArchive().getBlogInfo(h);
|
||||
if (info == null) {
|
||||
resp.sendError(404, "Blog does not exist");
|
||||
return;
|
||||
}
|
||||
File root = BlogManager.instance().getArchive().getArchiveDir();
|
||||
File blogDir = new File(root, blog);
|
||||
if (!blogDir.exists()) {
|
||||
resp.sendError(404, "Blog does not exist");
|
||||
return;
|
||||
}
|
||||
File entry = new File(blogDir, entryId + ".snd");
|
||||
if (!entry.exists()) {
|
||||
resp.sendError(404, "Entry does not exist");
|
||||
return;
|
||||
}
|
||||
resp.setContentType("application/x-syndie-post");
|
||||
dump(entry, resp);
|
||||
}
|
||||
|
||||
private void dump(File source, HttpServletResponse resp) throws ServletException, IOException {
|
||||
FileInputStream in = new FileInputStream(source);
|
||||
OutputStream out = resp.getOutputStream();
|
||||
byte buf[] = new byte[1024];
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
}
|
@@ -20,25 +20,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");
|
||||
private 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";
|
||||
@@ -79,70 +60,157 @@ public class ArchiveViewerBean {
|
||||
public static final String SEL_BLOGTAG = "blogtag://";
|
||||
public static final String SEL_ENTRY = "entry://";
|
||||
public static final String SEL_GROUP = "group://";
|
||||
/** submit field for the selector form */
|
||||
public static final String PARAM_SELECTOR_ACTION = "action";
|
||||
public static final String SEL_ACTION_SET_AS_DEFAULT = "Set as default";
|
||||
|
||||
public static void renderBlogSelector(User user, Map parameters, Writer out) throws IOException {
|
||||
out.write("<select name=\"");
|
||||
String sel = getString(parameters, PARAM_SELECTOR);
|
||||
String action = getString(parameters, PARAM_SELECTOR_ACTION);
|
||||
if ( (sel != null) && (action != null) && (SEL_ACTION_SET_AS_DEFAULT.equals(action)) ) {
|
||||
user.setDefaultSelector(HTMLRenderer.sanitizeString(sel, false));
|
||||
BlogManager.instance().saveUser(user);
|
||||
}
|
||||
|
||||
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("<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();
|
||||
out.write("<option value=\"group://" + Base64.encode(name.getBytes()) + "\">" +
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
ArchiveIndex index = archive.getIndex();
|
||||
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();
|
||||
|
||||
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://");
|
||||
out.write(blog);
|
||||
out.write("\">");
|
||||
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
|
||||
name = Base64.encode(cur.getData());
|
||||
out.write(name);
|
||||
out.write("- all posts</option>\n");
|
||||
out.write("</option>\n");
|
||||
}
|
||||
|
||||
////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 = 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);
|
||||
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);
|
||||
if (false) {
|
||||
StringBuffer b = new StringBuffer(tag.length()*2);
|
||||
for (int k = 0; k < tag.length(); k++) {
|
||||
b.append((int)tag.charAt(k));
|
||||
b.append(' ');
|
||||
}
|
||||
System.out.println("tag in select: " + tag + ": " + b.toString());
|
||||
}
|
||||
|
||||
if (!allTags.contains(tag))
|
||||
allTags.add(tag);
|
||||
out.write("<option value=\"blogtag://");
|
||||
out.write(blog);
|
||||
out.write("/");
|
||||
out.write(Base64.encode(tag));
|
||||
byte utf8tag[] = DataHelper.getUTF8(tag);
|
||||
String encoded = Base64.encode(utf8tag);
|
||||
if (false) {
|
||||
byte utf8dec[] = Base64.decode(encoded);
|
||||
String travel = DataHelper.getUTF8(utf8dec);
|
||||
StringBuffer b = new StringBuffer();
|
||||
for (int k = 0; k < travel.length(); k++) {
|
||||
b.append((int)travel.charAt(k));
|
||||
b.append(' ');
|
||||
}
|
||||
b.append(" encoded into: ");
|
||||
for (int k = 0; k < encoded.length(); k++) {
|
||||
b.append((int)encoded.charAt(k));
|
||||
b.append(' ');
|
||||
}
|
||||
System.out.println("UTF8(unbase64(base64(UTF8(tag)))) == tag: " + b.toString());
|
||||
}
|
||||
out.write(encoded);
|
||||
out.write("\">");
|
||||
out.write(name);
|
||||
out.write("- posts with the tag "");
|
||||
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://");
|
||||
out.write(Base64.encode(tag));
|
||||
out.write(Base64.encode(DataHelper.getUTF8(tag)));
|
||||
out.write("\">Posts in any blog with the tag "");
|
||||
out.write(tag);
|
||||
out.write(""</option>\n");
|
||||
}
|
||||
*/
|
||||
out.write("</select>");
|
||||
|
||||
int numPerPage = getInt(parameters, PARAM_NUM_PER_PAGE, 5);
|
||||
@@ -157,23 +225,42 @@ public class ArchiveViewerBean {
|
||||
|
||||
}
|
||||
|
||||
public static void renderBlogs(User user, Map parameters, Writer out) throws IOException {
|
||||
private static String getDefaultSelector(User user, Map parameters) {
|
||||
if ( (user == null) || (user.getDefaultSelector() == null) )
|
||||
return BlogManager.instance().getArchive().getDefaultSelector();
|
||||
else
|
||||
return user.getDefaultSelector();
|
||||
}
|
||||
|
||||
public static void renderBlogs(User user, Map parameters, Writer out, String afterPagination) throws IOException {
|
||||
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 = new String(Base64.decode(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);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
String group = getString(parameters, PARAM_GROUP);
|
||||
if (group != null) group = new String(Base64.decode(group));
|
||||
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) {
|
||||
Selector s = new Selector(sel);
|
||||
blog = s.blog;
|
||||
@@ -188,7 +275,7 @@ public class ArchiveViewerBean {
|
||||
boolean showImages = getBool(parameters, PARAM_SHOW_IMAGES, (user != null ? user.getShowImages() : false));
|
||||
boolean regenerateIndex = getBool(parameters, PARAM_REGENERATE_INDEX, false);
|
||||
try {
|
||||
renderBlogs(user, blog, tag, entryId, group, numPerPage, pageNum, expandEntries, showImages, regenerateIndex, out);
|
||||
renderBlogs(user, blog, tag, entryId, group, numPerPage, pageNum, expandEntries, showImages, regenerateIndex, sel, out, afterPagination);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
throw ioe;
|
||||
@@ -210,47 +297,93 @@ 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);
|
||||
if (tag != null) tag = new String(Base64.decode(tag));
|
||||
System.out.println("Selector [" + selector + "] blogString: [" + blogStr + "] tag: [" + tag + "]");
|
||||
String origTag = tag;
|
||||
byte rawDecode[] = null;
|
||||
if (tag != null) {
|
||||
rawDecode = Base64.decode(tag);
|
||||
tag = DataHelper.getUTF8(rawDecode);
|
||||
}
|
||||
//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++) {
|
||||
b.append((int)tag.charAt(j));
|
||||
if (rawDecode.length > j)
|
||||
b.append('.').append((int)rawDecode[j]);
|
||||
b.append(' ');
|
||||
}
|
||||
b.append("encoded as ");
|
||||
for (int j = 0; j < origTag.length(); j++) {
|
||||
b.append((int)origTag.charAt(j)).append(' ');
|
||||
}
|
||||
//System.out.println("selected tag: " + b.toString());
|
||||
}
|
||||
} else if (selector.startsWith(SEL_TAG)) {
|
||||
tag = selector.substring(SEL_TAG.length());
|
||||
if (tag != null) tag = new String(Base64.decode(tag));
|
||||
System.out.println("Selector [" + selector + "] tag: [" + tag + "]");
|
||||
byte rawDecode[] = null;
|
||||
if (tag != null) {
|
||||
rawDecode = Base64.decode(tag);
|
||||
tag = DataHelper.getUTF8(rawDecode);
|
||||
}
|
||||
//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++) {
|
||||
b.append((int)tag.charAt(j));
|
||||
if (rawDecode.length > j)
|
||||
b.append('.').append((int)rawDecode[j]);
|
||||
b.append(' ');
|
||||
}
|
||||
//System.out.println("selected tag: " + b.toString());
|
||||
}
|
||||
} else if (selector.startsWith(SEL_ENTRY)) {
|
||||
int entryStart = selector.lastIndexOf('/');
|
||||
String blogStr = selector.substring(SEL_ENTRY.length(), entryStart);
|
||||
String blogStr = blogStr = selector.substring(SEL_ENTRY.length(), entryStart);
|
||||
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 = new String(Base64.decode(selector.substring(SEL_GROUP.length())));
|
||||
System.out.println("Selector [" + selector + "] group: [" + group + "]");
|
||||
group = DataHelper.getUTF8(Base64.decode(selector.substring(SEL_GROUP.length())));
|
||||
//System.out.println("Selector [" + selector + "] group: [" + group + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderBlogs(User user, Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum,
|
||||
boolean expandEntries, boolean showImages, boolean regenerateIndex, Writer out) throws IOException {
|
||||
private static void renderBlogs(User user, Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum,
|
||||
boolean expandEntries, boolean showImages, boolean regenerateIndex, String selector, Writer out, String afterPagination) throws IOException {
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
if (regenerateIndex)
|
||||
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;
|
||||
@@ -268,26 +401,33 @@ public class ArchiveViewerBean {
|
||||
pages = entries.size() / numPerPage;
|
||||
if (numPerPage * pages < entries.size())
|
||||
pages++;
|
||||
out.write("<i>");
|
||||
if (pageNum > 0) {
|
||||
String prevURL = HTMLRenderer.getPageURL(blog, tag, entryId, group, numPerPage, pageNum-1, expandEntries, showImages);
|
||||
System.out.println("prevURL: " + prevURL);
|
||||
out.write(" <a href=\"" + prevURL + "\"><<</a>");
|
||||
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 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 = HTMLRenderer.getPageURL(blog, tag, entryId, group, numPerPage, pageNum+1, expandEntries, showImages);
|
||||
System.out.println("nextURL: " + nextURL);
|
||||
out.write(" <a href=\"" + nextURL + "\">>></a>");
|
||||
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 class=\"b_selectorNextMore\" href=\"" + nextURL + "\">>></a>");
|
||||
} else {
|
||||
out.write(" >>");
|
||||
out.write(" <span class=\"b_selectorNextNone\">>></span>");
|
||||
}
|
||||
out.write("</i>");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
out.write(" <i>");
|
||||
|
||||
if (showImages)
|
||||
@@ -305,9 +445,13 @@ public class ArchiveViewerBean {
|
||||
"\">Expand details</a>");
|
||||
|
||||
out.write("</i>");
|
||||
*/
|
||||
|
||||
if (afterPagination != null)
|
||||
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);
|
||||
@@ -323,7 +467,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));
|
||||
@@ -333,7 +479,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);
|
||||
@@ -342,14 +488,58 @@ 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 final String getString(Map parameters, String param) {
|
||||
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;
|
||||
Object vals = parameters.get(param);
|
||||
@@ -369,6 +559,24 @@ public class ArchiveViewerBean {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static final String[] getStrings(Map parameters, String param) {
|
||||
if ( (parameters == null) || (parameters.get(param) == null) )
|
||||
return null;
|
||||
Object vals = parameters.get(param);
|
||||
if (vals.getClass().isArray()) {
|
||||
return (String[])vals;
|
||||
} else if (vals instanceof Collection) {
|
||||
Collection c = (Collection)vals;
|
||||
if (c.size() <= 0) return null;
|
||||
String rv[] = new String[c.size()];
|
||||
int i = 0;
|
||||
for (Iterator iter = c.iterator(); iter.hasNext(); i++)
|
||||
rv[i] = (String)iter.next();
|
||||
return rv;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int getInt(Map param, String key, int defaultVal) {
|
||||
String val = getString(param, key);
|
||||
@@ -440,7 +648,7 @@ public class ArchiveViewerBean {
|
||||
}
|
||||
|
||||
private static void renderInvalidAttachment(Map parameters, OutputStream out) throws IOException {
|
||||
out.write("<b>No such entry, or no such attachment</b>".getBytes());
|
||||
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 {
|
||||
@@ -454,43 +662,44 @@ public class ArchiveViewerBean {
|
||||
return;
|
||||
}
|
||||
String props[] = info.getProperties();
|
||||
out.write("<table border=\"0\">");
|
||||
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");
|
||||
out.write("<tr class=\"b_metaField\"><td class=\"b_metaField\"><span class=\"b_metaField\">" + HTMLRenderer.sanitizeString(props[i])
|
||||
+ ":</span></td><td class=\"b_metaValue\"><span class=\"b_metaValue\">" + HTMLRenderer.sanitizeString(info.getProperty(props[i])) + "</span></td></tr>\n");
|
||||
}
|
||||
}
|
||||
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>");
|
||||
}
|
||||
out.write("</table>");
|
||||
} else {
|
||||
out.write("Blog not specified");
|
||||
out.write("<span class=\"b_metaMsgErr\">Blog not specified</span>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
apps/syndie/java/src/net/i2p/syndie/web/ExportServlet.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.syndie.*;
|
||||
import net.i2p.syndie.data.*;
|
||||
|
||||
/**
|
||||
* Dump out a whole series of blog metadata and entries as a zip stream. All metadata
|
||||
* is written before any entries, so it can be processed in order safely.
|
||||
*
|
||||
* HTTP parameters:
|
||||
* = meta (multiple values): base64 hash of the blog for which metadata is requested
|
||||
* = entry (multiple values): blog URI of an entry being requested
|
||||
*/
|
||||
public class ExportServlet extends HttpServlet {
|
||||
|
||||
public void doGet(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");
|
||||
resp.setContentType("application/x-syndie-zip");
|
||||
resp.setStatus(200);
|
||||
OutputStream out = resp.getOutputStream();
|
||||
ZipOutputStream zo = new ZipOutputStream(out);
|
||||
|
||||
List metaFiles = getMetaFiles(meta);
|
||||
|
||||
ZipEntry ze = null;
|
||||
byte buf[] = new byte[1024];
|
||||
int read = -1;
|
||||
for (int i = 0; metaFiles != null && i < metaFiles.size(); i++) {
|
||||
ze = new ZipEntry("meta" + i);
|
||||
ze.setTime(0);
|
||||
zo.putNextEntry(ze);
|
||||
FileInputStream in = new FileInputStream((File)metaFiles.get(i));
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
zo.write(buf, 0, read);
|
||||
zo.closeEntry();
|
||||
}
|
||||
|
||||
List entryFiles = getEntryFiles(entries);
|
||||
for (int i = 0; entryFiles != null && i < entryFiles.size(); i++) {
|
||||
ze = new ZipEntry("entry" + i);
|
||||
ze.setTime(0);
|
||||
zo.putNextEntry(ze);
|
||||
FileInputStream in = new FileInputStream((File)entryFiles.get(i));
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
zo.write(buf, 0, read);
|
||||
zo.closeEntry();
|
||||
}
|
||||
|
||||
zo.finish();
|
||||
zo.close();
|
||||
}
|
||||
|
||||
private static List getMetaFiles(String blogHashes[]) {
|
||||
if ( (blogHashes == null) || (blogHashes.length <= 0) ) return null;
|
||||
File dir = BlogManager.instance().getArchive().getArchiveDir();
|
||||
List rv = new ArrayList(blogHashes.length);
|
||||
for (int i = 0; i < blogHashes.length; i++) {
|
||||
byte hv[] = Base64.decode(blogHashes[i]);
|
||||
if ( (hv == null) || (hv.length != Hash.HASH_LENGTH) )
|
||||
continue;
|
||||
File blogDir = new File(dir, blogHashes[i]);
|
||||
File metaFile = new File(blogDir, Archive.METADATA_FILE);
|
||||
if (metaFile.exists())
|
||||
rv.add(metaFile);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static List getEntryFiles(String blogURIs[]) {
|
||||
if ( (blogURIs == null) || (blogURIs.length <= 0) ) return null;
|
||||
File dir = BlogManager.instance().getArchive().getArchiveDir();
|
||||
List rv = new ArrayList(blogURIs.length);
|
||||
for (int i = 0; i < blogURIs.length; i++) {
|
||||
BlogURI uri = new BlogURI(blogURIs[i]);
|
||||
if (uri.getEntryId() < 0)
|
||||
continue;
|
||||
File blogDir = new File(dir, uri.getKeyHash().toBase64());
|
||||
File entryFile = new File(blogDir, uri.getEntryId() + ".snd");
|
||||
if (entryFile.exists())
|
||||
rv.add(entryFile);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
174
apps/syndie/java/src/net/i2p/syndie/web/PostBean.java
Normal file
@@ -0,0 +1,174 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
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() {
|
||||
_context = I2PAppContext.getGlobalContext();
|
||||
_log = _context.logManager().getLog(PostBean.class);
|
||||
reinitialize();
|
||||
}
|
||||
|
||||
public void reinitialize() {
|
||||
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();
|
||||
if (_localFiles != null)
|
||||
for (int i = 0; i < _localFiles.size(); i++)
|
||||
((File)_localFiles.get(i)).delete();
|
||||
|
||||
_localFiles = new ArrayList();
|
||||
_previewed = false;
|
||||
}
|
||||
|
||||
public User getUser() { return _user; }
|
||||
public String getSubject() { return (_subject != null ? _subject : ""); }
|
||||
public String getTags() { return (_tags != null ? _tags : ""); }
|
||||
public String getText() { return (_text != null ? _text : ""); }
|
||||
public String getHeaders() { return (_headers != null ? _headers : ""); }
|
||||
public void setUser(User user) { _user = user; }
|
||||
public void setSubject(String subject) { _subject = subject; }
|
||||
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()) )
|
||||
return (String)_fileTypes.get(id);
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
public void writeAttachmentData(int id, OutputStream out) throws IOException {
|
||||
FileInputStream in = new FileInputStream((File)_localFiles.get(id));
|
||||
byte buf[] = new byte[1024];
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void addAttachment(String filename, InputStream fileStream, String mimeType) {
|
||||
_filenames.add(filename);
|
||||
_fileStreams.add(fileStream);
|
||||
_fileTypes.add(mimeType);
|
||||
}
|
||||
public int getAttachmentCount() { return (_filenames != null ? _filenames.size() : 0); }
|
||||
|
||||
public BlogURI postEntry() throws IOException {
|
||||
if (!_previewed) return null;
|
||||
List localStreams = new ArrayList(_localFiles.size());
|
||||
for (int i = 0; i < _localFiles.size(); i++) {
|
||||
File f = (File)_localFiles.get(i);
|
||||
localStreams.add(new FileInputStream(f));
|
||||
}
|
||||
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 {
|
||||
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(_context, _filenames, _fileTypes, _localFiles);
|
||||
r.render(_user, BlogManager.instance().getArchive(), null, smlContent, out, false, true);
|
||||
_previewed = true;
|
||||
}
|
||||
|
||||
private String renderSMLContent() {
|
||||
StringBuffer raw = new StringBuffer();
|
||||
raw.append("Subject: ").append(_subject).append('\n');
|
||||
raw.append("Tags: ");
|
||||
StringTokenizer tok = new StringTokenizer(_tags, " \t\n");
|
||||
while (tok.hasMoreTokens())
|
||||
raw.append(tok.nextToken()).append('\t');
|
||||
raw.append('\n');
|
||||
raw.append(_headers.trim());
|
||||
raw.append("\n\n");
|
||||
raw.append(_text.trim());
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
private void cacheAttachments() throws IOException {
|
||||
File postCacheDir = new File(BlogManager.instance().getTempDir(), _user.getBlog().toBase64());
|
||||
if (!postCacheDir.exists())
|
||||
postCacheDir.mkdirs();
|
||||
for (int i = 0; i < _fileStreams.size(); i++) {
|
||||
InputStream in = (InputStream)_fileStreams.get(i);
|
||||
File f = File.createTempFile("attachment", ".dat", postCacheDir);
|
||||
FileOutputStream o = new FileOutputStream(f);
|
||||
byte buf[] = new byte[1024];
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
o.write(buf, 0, read);
|
||||
o.close();
|
||||
in.close();
|
||||
_localFiles.add(f);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Caching attachment " + i + " temporarily in "
|
||||
+ f.getAbsolutePath() + " w/ " + f.length() + "bytes");
|
||||
}
|
||||
_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();
|
||||
}
|
||||
}
|
754
apps/syndie/java/src/net/i2p/syndie/web/RemoteArchiveBean.java
Normal file
@@ -0,0 +1,754 @@
|
||||
package net.i2p.syndie.web;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.*;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.EepGetScheduler;
|
||||
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;
|
||||
private int _proxyPort;
|
||||
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() {
|
||||
_remoteSchema = null;
|
||||
_remoteLocation = null;
|
||||
_remoteIndex = null;
|
||||
_fetchIndexInProgress = false;
|
||||
_proxyHost = null;
|
||||
_proxyPort = -1;
|
||||
_exportCapable = false;
|
||||
_statusMessages = new ArrayList();
|
||||
}
|
||||
|
||||
public String getRemoteSchema() { return _remoteSchema; }
|
||||
public String getRemoteLocation() { return _remoteLocation; }
|
||||
public ArchiveIndex getRemoteIndex() { return _remoteIndex; }
|
||||
public String getProxyHost() { return _proxyHost; }
|
||||
public int getProxyPort() { return _proxyPort; }
|
||||
public boolean getFetchIndexInProgress() { return _fetchIndexInProgress; }
|
||||
public String getStatus() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
while (_statusMessages.size() > 0)
|
||||
buf.append(_statusMessages.remove(0)).append("\n");
|
||||
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;
|
||||
Set blogs = new HashSet();
|
||||
if ("ALL".equals(meta)) {
|
||||
Set localBlogs = BlogManager.instance().getArchive().getIndex().getUniqueBlogs();
|
||||
Set remoteBlogs = _remoteIndex.getUniqueBlogs();
|
||||
for (Iterator iter = remoteBlogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
if (!localBlogs.contains(blog)) {
|
||||
if (!ignoreBlog(user, blog))
|
||||
blogs.add(blog);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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());
|
||||
for (Iterator iter = blogs.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
urls.add(buildMetaURL(blog));
|
||||
try {
|
||||
tmpFiles.add(File.createTempFile("fetchMeta", ".txt", BlogManager.instance().getTempDir()));
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + blog.toBase64() + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < urls.size(); i++)
|
||||
_statusMessages.add("Scheduling up metadata fetches for " + HTMLRenderer.sanitizeString((String)urls.get(i)));
|
||||
fetch(urls, tmpFiles, user, new MetadataStatusListener());
|
||||
}
|
||||
|
||||
private String buildMetaURL(Hash blog) {
|
||||
String loc = _remoteLocation.trim();
|
||||
int root = loc.lastIndexOf('/');
|
||||
return loc.substring(0, root + 1) + blog.toBase64() + "/" + Archive.METADATA_FILE;
|
||||
}
|
||||
|
||||
public void fetchSelectedEntries(User user, Map parameters) {
|
||||
String entries[] = ArchiveViewerBean.getStrings(parameters, "entry");
|
||||
if ( (entries == null) || (entries.length <= 0) ) return;
|
||||
List urls = new ArrayList(entries.length);
|
||||
List tmpFiles = new ArrayList(entries.length);
|
||||
for (int i = 0; i < entries.length; 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) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + HTMLRenderer.sanitizeString(entries[i]) + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < urls.size(); i++)
|
||||
_statusMessages.add("Scheduling blog post fetching for " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener());
|
||||
}
|
||||
|
||||
public void fetchSelectedBulk(User user, Map parameters) {
|
||||
String entries[] = ArchiveViewerBean.getStrings(parameters, "entry");
|
||||
String action = ArchiveViewerBean.getString(parameters, "action");
|
||||
if ("Fetch all new entries".equals(action)) {
|
||||
ArchiveIndex localIndex = BlogManager.instance().getArchive().getIndex();
|
||||
List uris = new ArrayList();
|
||||
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);
|
||||
if (!localIndex.getEntryIsKnown(uri))
|
||||
uris.add(uri);
|
||||
}
|
||||
matches.clear();
|
||||
}
|
||||
entries = new String[uris.size()];
|
||||
for (int i = 0; i < uris.size(); i++)
|
||||
entries[i] = ((BlogURI)uris.get(i)).toString();
|
||||
}
|
||||
if ( (entries == null) || (entries.length <= 0) ) return;
|
||||
if (_exportCapable) {
|
||||
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 bulk blog post fetch of " + HTMLRenderer.sanitizeString(entries[i]));
|
||||
}
|
||||
}
|
||||
for (Iterator iter = meta.iterator(); iter.hasNext(); ) {
|
||||
Hash blog = (Hash)iter.next();
|
||||
url.append("meta=").append(blog.toBase64()).append('&');
|
||||
_statusMessages.add("Scheduling bulk blog metadata fetch of " + 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());
|
||||
}
|
||||
} 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildExportURL() {
|
||||
String loc = _remoteLocation.trim();
|
||||
int root = loc.lastIndexOf('/');
|
||||
return loc.substring(0, root + 1) + "export.zip?";
|
||||
}
|
||||
|
||||
private String buildEntryURL(BlogURI uri) {
|
||||
String loc = _remoteLocation.trim();
|
||||
int root = loc.lastIndexOf('/');
|
||||
return loc.substring(0, root + 1) + uri.getKeyHash().toBase64() + "/" + uri.getEntryId() + ".snd";
|
||||
}
|
||||
|
||||
public void fetchAllEntries(User user, Map parameters) {
|
||||
ArchiveIndex localIndex = BlogManager.instance().getArchive().getIndex();
|
||||
List uris = new ArrayList();
|
||||
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);
|
||||
if (!localIndex.getEntryIsKnown(uri))
|
||||
uris.add(uri);
|
||||
}
|
||||
entries.clear();
|
||||
}
|
||||
List urls = new ArrayList(uris.size());
|
||||
List tmpFiles = new ArrayList(uris.size());
|
||||
for (int i = 0; i < uris.size(); i++) {
|
||||
urls.add(buildEntryURL((BlogURI)uris.get(i)));
|
||||
try {
|
||||
tmpFiles.add(File.createTempFile("fetchBlog", ".txt", BlogManager.instance().getTempDir()));
|
||||
} catch (IOException ioe) {
|
||||
_statusMessages.add("Internal error creating temporary file to fetch " + HTMLRenderer.sanitizeString(uris.get(i).toString()) + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < urls.size(); i++)
|
||||
_statusMessages.add("Fetch all entries: " + HTMLRenderer.sanitizeString((String)urls.get(i)));
|
||||
fetch(urls, tmpFiles, user, new BlogStatusListener());
|
||||
}
|
||||
|
||||
private void fetch(List urls, List tmpFiles, User user, EepGet.StatusListener lsnr) {
|
||||
EepGetScheduler scheduler = new EepGetScheduler(I2PAppContext.getGlobalContext(), urls, tmpFiles, _proxyHost, _proxyPort, lsnr);
|
||||
scheduler.fetch();
|
||||
}
|
||||
|
||||
public void fetchIndex(User user, String schema, String location, String proxyHost, String proxyPort) {
|
||||
_fetchIndexInProgress = true;
|
||||
_remoteIndex = null;
|
||||
_remoteLocation = location;
|
||||
_remoteSchema = schema;
|
||||
_proxyHost = null;
|
||||
_proxyPort = -1;
|
||||
_exportCapable = false;
|
||||
|
||||
if ( (schema == null) || (schema.trim().length() <= 0) ||
|
||||
(location == null) || (location.trim().length() <= 0) ) {
|
||||
_statusMessages.add("Location must be specified");
|
||||
_fetchIndexInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ("web".equals(schema)) {
|
||||
if ( (proxyHost != null) && (proxyHost.trim().length() > 0) &&
|
||||
(proxyPort != null) && (proxyPort.trim().length() > 0) ) {
|
||||
_proxyHost = proxyHost;
|
||||
try {
|
||||
_proxyPort = Integer.parseInt(proxyPort);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_statusMessages.add("Proxy port " + HTMLRenderer.sanitizeString(proxyPort) + " is invalid");
|
||||
_fetchIndexInProgress = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_statusMessages.add(new String("Remote schema " + HTMLRenderer.sanitizeString(schema) + " currently not supported"));
|
||||
_fetchIndexInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_statusMessages.add("Fetching index from " + HTMLRenderer.sanitizeString(_remoteLocation) +
|
||||
(_proxyHost != null ? " via " + HTMLRenderer.sanitizeString(_proxyHost) + ":" + _proxyPort : ""));
|
||||
File archiveFile = new File(BlogManager.instance().getTempDir(), user.getBlog().toBase64() + "_remoteArchive.txt");
|
||||
archiveFile.delete();
|
||||
EepGet eep = new EepGet(I2PAppContext.getGlobalContext(), ((_proxyHost != null) && (_proxyPort > 0)),
|
||||
_proxyHost, _proxyPort, 0, archiveFile.getAbsolutePath(), location);
|
||||
eep.addStatusListener(new IndexFetcherStatusListener(archiveFile));
|
||||
eep.fetch();
|
||||
}
|
||||
|
||||
private class IndexFetcherStatusListener implements EepGet.StatusListener {
|
||||
private File _archiveFile;
|
||||
public IndexFetcherStatusListener(File file) {
|
||||
_archiveFile = file;
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
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");
|
||||
_fetchIndexInProgress = false;
|
||||
ArchiveIndex i = new ArchiveIndex(I2PAppContext.getGlobalContext(), false);
|
||||
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 {
|
||||
public MetadataStatusListener() {}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
public BlogStatusListener() {}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (url.endsWith(".snm")) {
|
||||
handleMetadata(url, outputFile);
|
||||
return;
|
||||
}
|
||||
_statusMessages.add("Fetch of " + HTMLRenderer.sanitizeString(url) + " successful");
|
||||
File file = new File(outputFile);
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
EntryContainer c = new EntryContainer();
|
||||
in = new FileInputStream(file);
|
||||
c.load(in);
|
||||
BlogURI uri = c.getURI();
|
||||
if ( (uri == null) || (uri.getKeyHash() == null) ) {
|
||||
_statusMessages.add("Blog post at " + HTMLRenderer.sanitizeString(url) + " was corrupt - no URI");
|
||||
return;
|
||||
}
|
||||
Archive a = BlogManager.instance().getArchive();
|
||||
BlogInfo info = a.getBlogInfo(uri);
|
||||
if (info == null) {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " cannot be imported, as we don't have their blog metadata");
|
||||
return;
|
||||
}
|
||||
boolean ok = a.storeEntry(c);
|
||||
if (!ok) {
|
||||
_statusMessages.add("Blog post at " + url + ": " + uri.toString() + " has an invalid signature");
|
||||
return;
|
||||
} else {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " imported");
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error importing", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
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) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive the status of a fetch for the zip containing blogs and metadata (as generated by
|
||||
* the ExportServlet)
|
||||
*/
|
||||
private class BulkFetchListener implements EepGet.StatusListener {
|
||||
private File _tmp;
|
||||
public BulkFetchListener(File tmp) {
|
||||
_tmp = tmp;
|
||||
}
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_statusMessages.add("Attempt " + currentAttempt + " failed after " + bytesTransferred + (cause != null ? cause.getMessage() : ""));
|
||||
}
|
||||
|
||||
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.substring(0, url.indexOf('?'))) + " successful, importing the data");
|
||||
File file = new File(outputFile);
|
||||
ZipInputStream zi = null;
|
||||
try {
|
||||
zi = new ZipInputStream(new FileInputStream(file));
|
||||
|
||||
while (true) {
|
||||
ZipEntry entry = zi.getNextEntry();
|
||||
if (entry == null)
|
||||
break;
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
byte buf[] = new byte[1024];
|
||||
int read = -1;
|
||||
while ( (read = zi.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
|
||||
if (entry.getName().startsWith("meta")) {
|
||||
BlogInfo i = new BlogInfo();
|
||||
i.load(new ByteArrayInputStream(out.toByteArray()));
|
||||
boolean ok = BlogManager.instance().getArchive().storeBlogInfo(i);
|
||||
if (ok) {
|
||||
_statusMessages.add("Blog info for " + HTMLRenderer.sanitizeString(i.getProperty(BlogInfo.NAME)) + " imported");
|
||||
} else {
|
||||
_statusMessages.add("Blog info at " + HTMLRenderer.sanitizeString(url) + " was corrupt / invalid / forged");
|
||||
}
|
||||
} else if (entry.getName().startsWith("entry")) {
|
||||
EntryContainer c = new EntryContainer();
|
||||
c.load(new ByteArrayInputStream(out.toByteArray()));
|
||||
BlogURI uri = c.getURI();
|
||||
if ( (uri == null) || (uri.getKeyHash() == null) ) {
|
||||
_statusMessages.add("Blog post " + HTMLRenderer.sanitizeString(entry.getName()) + " was corrupt - no URI");
|
||||
continue;
|
||||
}
|
||||
Archive a = BlogManager.instance().getArchive();
|
||||
BlogInfo info = a.getBlogInfo(uri);
|
||||
if (info == null) {
|
||||
_statusMessages.add("Blog post " + HTMLRenderer.sanitizeString(entry.getName()) + " cannot be imported, as we don't have their blog metadata");
|
||||
continue;
|
||||
}
|
||||
boolean ok = a.storeEntry(c);
|
||||
if (!ok) {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " has an invalid signature");
|
||||
continue;
|
||||
} else {
|
||||
_statusMessages.add("Blog post " + uri.toString() + " imported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
} catch (IOException ioe) {
|
||||
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) {}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_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);
|
||||
}
|
||||
|
||||
private void post(List blogURIs, User user) {
|
||||
List files = new ArrayList(blogURIs.size()+1);
|
||||
Set meta = new HashSet(4);
|
||||
Map uploads = new HashMap(files.size());
|
||||
String importURL = getImportURL();
|
||||
_statusMessages.add("Uploading through " + HTMLRenderer.sanitizeString(importURL));
|
||||
for (int i = 0; i < blogURIs.size(); i++) {
|
||||
BlogURI uri = (BlogURI)blogURIs.get(i);
|
||||
File blogDir = new File(BlogManager.instance().getArchive().getArchiveDir(), uri.getKeyHash().toBase64());
|
||||
BlogInfo info = BlogManager.instance().getArchive().getBlogInfo(uri);
|
||||
if (!meta.contains(uri.getKeyHash())) {
|
||||
uploads.put("blogmeta" + meta.size(), new File(blogDir, Archive.METADATA_FILE));
|
||||
meta.add(uri.getKeyHash());
|
||||
_statusMessages.add("Scheduling upload of the blog metadata for " + HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME)));
|
||||
}
|
||||
uploads.put("blogpost" + i, new File(blogDir, uri.getEntryId() + ".snd"));
|
||||
_statusMessages.add("Scheduling upload of " + HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME))
|
||||
+ ": " + getEntryDate(uri.getEntryId()));
|
||||
}
|
||||
EepPost post = new EepPost();
|
||||
post.postFiles(importURL, _proxyHost, _proxyPort, uploads, new Runnable() { public void run() { _statusMessages.add("Upload complete"); } });
|
||||
}
|
||||
|
||||
private String getImportURL() {
|
||||
String loc = _remoteLocation.trim();
|
||||
int archiveRoot = loc.lastIndexOf('/');
|
||||
int syndieRoot = loc.lastIndexOf('/', archiveRoot-1);
|
||||
return loc.substring(0, syndieRoot + 1) + "import.jsp";
|
||||
}
|
||||
|
||||
public void renderDeltaForm(User user, ArchiveIndex localIndex, Writer out) throws IOException {
|
||||
Archive archive = BlogManager.instance().getArchive();
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
if (newBlogs > 0) {
|
||||
out.write(buf.toString());
|
||||
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 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 class=\"b_remBlog\"><td class=\"b_remBlog\" colspan=\"5\" align=\"left\" valign=\"top\">\n");
|
||||
BlogInfo info = archive.getBlogInfo(blog);
|
||||
if (info != null) {
|
||||
buf.append("<a class=\"b_remBlog\" href=\"");
|
||||
buf.append(HTMLRenderer.getPageURL(blog, null, -1, -1, -1, user.getShowExpanded(), user.getShowImages()));
|
||||
buf.append("\">").append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.NAME))).append("</a>: ");
|
||||
buf.append("<span class=\"b_remBlogDesc\">").append(HTMLRenderer.sanitizeString(info.getProperty(BlogInfo.DESCRIPTION)));
|
||||
buf.append("</span>\n");
|
||||
} else {
|
||||
buf.append("<span class=\"b_remBlog\">" + blog.toBase64() + "</span>\n");
|
||||
}
|
||||
buf.append("</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 class=\"b_remDetail\">\n");
|
||||
if (!archive.getIndex().getEntryIsKnown(uri)) {
|
||||
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 class=\"b_remDetail\"><a class=\"b_remLocal\" href=\"" + page + "\">(local)</a></td>\n");
|
||||
}
|
||||
buf.append("<td class=\"b_remDetail\"><span class=\"b_remDate\">" + getDate(uri.getEntryId()) + "</span></td>\n");
|
||||
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 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");
|
||||
}
|
||||
if (shownEntries > 0) {
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
}
|
||||
int remote = shownEntries;
|
||||
|
||||
// now for posts in known blogs that we have and they don't
|
||||
entries.clear();
|
||||
localIndex.selectMatchesOrderByEntryId(entries, blog, null);
|
||||
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 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 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 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");
|
||||
}
|
||||
}
|
||||
|
||||
if (shownEntries > remote) // skip blogs we have already syndicated
|
||||
out.write(buf.toString());
|
||||
}
|
||||
|
||||
// now for posts in blogs we have and they don't
|
||||
int newBefore = localNew;
|
||||
buf.setLength(0);
|
||||
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;
|
||||
}
|
||||
|
||||
entries.clear();
|
||||
localIndex.selectMatchesOrderByEntryId(entries, blog, null);
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
BlogURI uri = (BlogURI)entries.get(i);
|
||||
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 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");
|
||||
localNew++;
|
||||
}
|
||||
}
|
||||
if (localNew > newBefore)
|
||||
out.write(buf.toString());
|
||||
|
||||
out.write("</table>\n");
|
||||
if (newEntries > 0) {
|
||||
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("<span class=\"b_remNoRemotePosts\">" + HTMLRenderer.sanitizeString(_remoteLocation) + " has no new posts to offer us</span>\n");
|
||||
}
|
||||
if (localNew > 0) {
|
||||
out.write("<input class=\"b_remPostSelected\" type=\"submit\" name=\"action\" value=\"Post selected entries\" /> \n");
|
||||
}
|
||||
out.write("<hr />\n");
|
||||
}
|
||||
private final SimpleDateFormat _dateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.UK);
|
||||
private String getDate(long when) {
|
||||
synchronized (_dateFormat) {
|
||||
return _dateFormat.format(new Date(when));
|
||||
}
|
||||
}
|
||||
private final String getEntryDate(long when) {
|
||||
synchronized (_dateFormat) {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(when));
|
||||
long dayBegin = _dateFormat.parse(str).getTime();
|
||||
return str + "." + (when - dayBegin);
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
// wtf
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long getId(long id) {
|
||||
synchronized (_dateFormat) {
|
||||
try {
|
||||
String str = _dateFormat.format(new Date(id));
|
||||
long dayBegin = _dateFormat.parse(str).getTime();
|
||||
return (id - dayBegin);
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
// wtf
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,39 @@
|
||||
<%@page import="net.i2p.syndie.web.ArchiveViewerBean, net.i2p.syndie.*" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<form action="index.jsp">
|
||||
<b>Blogs:</b> <%ArchiveViewerBean.renderBlogSelector(user, request.getParameterMap(), out);%>
|
||||
<input type="submit" value="Refresh" /></form>
|
||||
<hr />
|
||||
<%@page contentType="text/html; charset=UTF-8" import="net.i2p.syndie.web.ArchiveViewerBean, net.i2p.syndie.*" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<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")));
|
||||
|
||||
<%ArchiveViewerBean.renderBlogs(user, request.getParameterMap(), out); out.flush(); %>
|
||||
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,28 +1,3 @@
|
||||
<%@page import="net.i2p.syndie.web.ArchiveViewerBean, net.i2p.syndie.*, net.i2p.data.Base64" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.data.ArchiveIndex" id="archive" />
|
||||
<%if (request.getRequestURI().indexOf("register.jsp") == -1) {%>
|
||||
<jsp:include page="_leftnavprotected.jsp" />
|
||||
<hr />
|
||||
<% } %>
|
||||
<u>Local archive:</u><br />
|
||||
<b>Posts:</b> <jsp:getProperty name="archive" property="newEntries" />/<jsp:getProperty name="archive" property="allEntries" /><br />
|
||||
<b>Blogs:</b> <jsp:getProperty name="archive" property="newBlogs" />/<jsp:getProperty name="archive" property="allBlogs" /><br />
|
||||
<b>Size:</b> <jsp:getProperty name="archive" property="newSizeStr" />/<jsp:getProperty name="archive" property="totalSizeStr" /><br />
|
||||
<i>(new/total)</i>
|
||||
<hr />
|
||||
<u>Latest blogs:</u><br />
|
||||
<%!int i = 0; %>
|
||||
<%for (i = 0; i < archive.getNewestBlogCount(); i++) {
|
||||
String keyHash = Base64.encode(archive.getNewestBlog(i).getData());
|
||||
%><a href="viewmetadata.jsp?<%=ArchiveViewerBean.PARAM_BLOG%>=<%=keyHash%>">
|
||||
<%=ArchiveViewerBean.getBlogName(keyHash)%></a><br />
|
||||
<% } %>
|
||||
<hr />
|
||||
<u>Latest posts:</u><br />
|
||||
<%for (i = 0; i < archive.getNewestBlogEntryCount(); i++) {
|
||||
String keyHash = Base64.encode(archive.getNewestBlogEntry(i).getKeyHash().getData());
|
||||
long entryId = archive.getNewestBlogEntry(i).getEntryId();
|
||||
%><a href="index.jsp?<%=ArchiveViewerBean.PARAM_BLOG%>=<%=keyHash%>&<%=ArchiveViewerBean.PARAM_ENTRY%>=<%=entryId%>&<%=ArchiveViewerBean.PARAM_EXPAND_ENTRIES%>=true">
|
||||
<%=ArchiveViewerBean.getEntryTitle(keyHash, entryId)%></a><br />
|
||||
<% } %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.data.TransparentArchiveIndex" id="archive" />
|
@@ -1,41 +0,0 @@
|
||||
<%@page import="net.i2p.syndie.*, net.i2p.syndie.sml.*" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.data.ArchiveIndex" id="archive" />
|
||||
<%
|
||||
if ("true".equals(request.getParameter("logout"))) {
|
||||
user.invalidate();
|
||||
}
|
||||
String login = request.getParameter("login");
|
||||
String pass = request.getParameter("password");
|
||||
String loginSubmit = request.getParameter("Login");
|
||||
if ( (login != null) && (pass != null) && (loginSubmit != null) && (loginSubmit.equals("Login")) ) {
|
||||
String loginResult = BlogManager.instance().login(user, login, pass);
|
||||
out.write("<b>" + loginResult + "</b>");
|
||||
}
|
||||
|
||||
if (user.getAuthenticated()) {%>
|
||||
<b><u><jsp:getProperty property="username" name="user" />:</u></b><br />
|
||||
<a href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())%>">My blog</a><br />
|
||||
<a href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, user.getMostRecentEntry(), -1, -1, true, user.getShowImages())%>">Last post</a><br />
|
||||
<a href="<%=HTMLRenderer.getPostURL(user.getBlog())%>">Post</a><br />
|
||||
<a href="<%=HTMLRenderer.getMetadataURL(user.getBlog())%>">Metadata</a><br />
|
||||
<a href="index.jsp?logout=true">Logout</a><br />
|
||||
<!--
|
||||
<hr />
|
||||
<u>Remote Archives:</u><br />
|
||||
<a href="viewarchive.jsp?url=eep://politics.i2p/archive/">politics.i2p</a><br />
|
||||
<a href="viewarchive.jsp?url=freenet://SSK@.../TFE/archive/">TFE</a><br />
|
||||
-->
|
||||
<%} else {%>
|
||||
<form action="<%=request.getRequestURI() + "?" + (request.getQueryString() != null ? request.getQueryString() : "")%>">
|
||||
<b>Login:</b> <input type="text" name="login" size="8" /><br />
|
||||
<b>Pass:</b> <input type="password" name="password" size="8" /><br /><%
|
||||
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" /><br /></form>
|
||||
<a href="register.jsp">Register</a><br />
|
||||
<% } %>
|
@@ -1,7 +1,5 @@
|
||||
<%@page import="net.i2p.syndie.BlogManager" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.data.ArchiveIndex" id="archive" />
|
||||
<% session.setAttribute("archive", BlogManager.instance().getArchive().getIndex()); %>
|
||||
<!--
|
||||
<center>[syndiemedia]</center>
|
||||
-->
|
@@ -1,3 +1,46 @@
|
||||
<td valign="top" align="left" bgcolor="#cccc88" height="10"><a href="index.jsp">Blogs</a></td>
|
||||
<td valign="top" align="left" bgcolor="#cccc88" height="10">Remote archives</td>
|
||||
<td valign="top" align="left" bgcolor="#cccc88" height="10">Manage</td>
|
||||
<%@page import="net.i2p.syndie.*, net.i2p.syndie.sml.*, net.i2p.syndie.web.*" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<form action="<%=request.getRequestURI() + "?" + (request.getQueryString() != null ? request.getQueryString() : "")%>">
|
||||
<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");
|
||||
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 class=\"b_topnavLoginResult\">" + loginResult + "</b>");
|
||||
}
|
||||
%>
|
||||
<% if (user.getAuthenticated()) { %>
|
||||
<span class="b_topnavUsername">Logged in as:</span> <em class="b_topnavUsername"><jsp:getProperty property="username" name="user" />:</em>
|
||||
<a class="b_topnavBlog" href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, -1, -1, -1, user.getShowExpanded(), user.getShowImages())%>"><%=HTMLRenderer.sanitizeString(ArchiveViewerBean.getBlogName(user.getBlogStr()))%></a>
|
||||
<a class="b_topnavPost" href="<%=HTMLRenderer.getPostURL(user.getBlog())%>">Post</a>
|
||||
<a class="b_topnavMeta" href="<%=HTMLRenderer.getMetadataURL(user.getBlog())%>">Metadata</a>
|
||||
<a class="b_topnavAddr" href="addresses.jsp">Addressbook</a>
|
||||
<a class="b_topnavLogout" href="index.jsp?logout=true">Logout</a>
|
||||
<%} else {%>
|
||||
<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 class="b_topnavLoginSubmit" type="submit" name="Login" value="Login" />
|
||||
<a class="b_topnavRegister" href="register.jsp">Register</a>
|
||||
<% } %>
|
||||
</td>
|
||||
</form>
|
@@ -1,45 +0,0 @@
|
||||
<%@page import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.*" %>
|
||||
<jsp:useBean scope="session" class="net.i2p.syndie.User" id="user" />
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia</title>
|
||||
</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 = new String(Base64.decode(nameStr));
|
||||
location = new String(Base64.decode(locStr));
|
||||
schema = new String(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.*, 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 userhosts.txt:</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,32 +1,36 @@
|
||||
<%@page import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*" %>
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.data.*, net.i2p.syndie.web.*, net.i2p.syndie.sml.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><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");
|
||||
String desc = request.getParameter("description");
|
||||
if (loc != null) loc = HTMLRenderer.sanitizeString(new String(Base64.decode(loc)));
|
||||
if (schema != null) schema = HTMLRenderer.sanitizeString(new String(Base64.decode(schema)));
|
||||
if (desc != null) desc = HTMLRenderer.sanitizeString(new String(Base64.decode(desc)));
|
||||
if (loc != null) loc = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(loc)));
|
||||
if (schema != null) schema = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(schema)));
|
||||
if (desc != null) desc = HTMLRenderer.sanitizeString(DataHelper.getUTF8(Base64.decode(desc)));
|
||||
|
||||
if ( (loc != null) && (schema != null) ) {
|
||||
out.write(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>
|
68
apps/syndie/jsp/import.jsp
Normal file
@@ -0,0 +1,68 @@
|
||||
<%@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" >
|
||||
</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"><%
|
||||
|
||||
String contentType = request.getContentType();
|
||||
if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
MultiPartRequest req = new MultiPartRequest(request);
|
||||
int metaId = 0;
|
||||
while (true) {
|
||||
InputStream meta = req.getInputStream("blogmeta" + metaId);
|
||||
if ( (meta == null) || (meta.available() <= 0) )
|
||||
break;
|
||||
if (!BlogManager.instance().importBlogMetadata(meta)) {
|
||||
%><span class="b_importMsgErr">Metadata <%=metaId%> failed to be imported</span><br /><%
|
||||
break;
|
||||
}
|
||||
metaId++;
|
||||
}
|
||||
int entryId = 0;
|
||||
while (true) {
|
||||
InputStream entry = req.getInputStream("blogpost" + entryId);
|
||||
if ( (entry == null) || (entry.available() <= 0) )
|
||||
break;
|
||||
if (!BlogManager.instance().importBlogEntry(entry)) {
|
||||
%><span class="b_importMsgErr">Entry <%=entryId%> failed to be imported</span><br /><%
|
||||
break;
|
||||
}
|
||||
entryId++;
|
||||
}
|
||||
|
||||
if ( (entryId > 0) || (metaId > 0) ) {
|
||||
BlogManager.instance().getArchive().regenerateIndex();
|
||||
session.setAttribute("index", BlogManager.instance().getArchive().getIndex());
|
||||
}
|
||||
%><span class="b_importMsgOk">Imported <%=entryId%> posts and <%=metaId%> blog metadata files.</span>
|
||||
<%
|
||||
} else { %><form action="import.jsp" method="POST" enctype="multipart/form-data">
|
||||
<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 class="b_importSubmit" type="submit" name="Post" value="Post entry" /> <input class="b_importCancel" type="reset" value="Cancel" />
|
||||
<% } %>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
@@ -1,14 +1,27 @@
|
||||
<%@page contentType="text/html" import="net.i2p.syndie.web.*" %>
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
<link href="rss.jsp?<%
|
||||
if (request.getParameter("blog") != null)
|
||||
out.write("blog=" + request.getParameter("blog") + "&");
|
||||
if (request.getParameter("entry") != null)
|
||||
out.write("entry=" + request.getParameter("entry") + "&");
|
||||
if (request.getParameter("tag") != null)
|
||||
out.write("tag=" + request.getParameter("tag") + "&");
|
||||
if (request.getParameter("selector") != null)
|
||||
out.write("selector=" + request.getParameter("selector") + "&");
|
||||
%>" rel="alternate" type="application/rss+xml" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><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,74 +1,137 @@
|
||||
<%@page 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.*" %>
|
||||
<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.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>
|
||||
<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"><%
|
||||
|
||||
String contentType = request.getContentType();
|
||||
if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
if (!user.getAuthenticated()) { %>You must be logged in to post<%
|
||||
} else {
|
||||
MultiPartRequest req = new MultiPartRequest(request);
|
||||
String entrySubject = req.getString("entrysubject");
|
||||
String entryTags = req.getString("entrytags");
|
||||
String entryText = req.getString("entrytext");
|
||||
String entryHeaders = req.getString("entryheaders");
|
||||
String 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);
|
||||
} else {
|
||||
replyTo = null;
|
||||
}
|
||||
if (!user.getAuthenticated()) {
|
||||
%><span class="b_postMsgErr">You must be logged in to post</span><%
|
||||
} else {
|
||||
String confirm = request.getParameter("action");
|
||||
if ( (confirm != null) && (confirm.equalsIgnoreCase("confirm")) ) {
|
||||
String archive = request.getParameter("archive");
|
||||
post.setArchive(archive);
|
||||
BlogURI uri = post.postEntry();
|
||||
if (uri != null) {
|
||||
%><span class="b_postMsgOk">Blog entry <a class="b_postOkLink" href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, uri.getEntryId(), -1, -1,
|
||||
user.getShowExpanded(), user.getShowImages())%>">posted</a>!</span><%
|
||||
} else {
|
||||
%><span class="b_postMsgErro">There was an unknown error posting the entry...</span><%
|
||||
}
|
||||
|
||||
List fileStreams = new ArrayList();
|
||||
List fileNames = new ArrayList();
|
||||
List fileTypes = new ArrayList();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
String filename = req.getFilename("entryfile" + i);
|
||||
if ( (filename != null) && (filename.trim().length() > 0) ) {
|
||||
fileNames.add(filename.trim());
|
||||
fileStreams.add(req.getInputStream("entryfile" + i));
|
||||
Hashtable params = req.getParams("entryfile" + i);
|
||||
String type = "application/octet-stream";
|
||||
for (Iterator iter = params.keySet().iterator(); iter.hasNext(); ) {
|
||||
String cur = (String)iter.next();
|
||||
if ("content-type".equalsIgnoreCase(cur)) {
|
||||
type = (String)params.get(cur);
|
||||
break;
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
} else {
|
||||
// logged in but not confirmed...
|
||||
String contentType = request.getContentType();
|
||||
if ((contentType != null) && (contentType.indexOf("boundary=") != -1) ) {
|
||||
// not confirmed but they posted stuff... gobble up what they give
|
||||
// and display it as a preview (then we show the confirm form)
|
||||
post.reinitialize();
|
||||
post.setUser(user);
|
||||
|
||||
MultiPartRequest req = new MultiPartRequest(request);
|
||||
String entrySubject = req.getString("entrysubject");
|
||||
String entryTags = req.getString("entrytags");
|
||||
String entryText = req.getString("entrytext");
|
||||
String entryHeaders = req.getString("entryheaders");
|
||||
String style = req.getString("style");
|
||||
if ( (style != null) && (style.trim().length() > 0) ) {
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_STYLE + ": " + style;
|
||||
}
|
||||
String replyTo = req.getString(ArchiveViewerBean.PARAM_IN_REPLY_TO);
|
||||
if ( (replyTo != null) && (replyTo.trim().length() > 0) ) {
|
||||
byte r[] = Base64.decode(replyTo);
|
||||
if (r != null) {
|
||||
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
|
||||
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
|
||||
} else {
|
||||
replyTo = null;
|
||||
}
|
||||
}
|
||||
fileTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
BlogURI entry = BlogManager.instance().createBlogEntry(user, entrySubject, entryTags, entryHeaders, entryText, fileNames, fileStreams, fileTypes);
|
||||
if (entry != null) {
|
||||
// it has been rebuilt...
|
||||
request.setAttribute("index", BlogManager.instance().getArchive().getIndex());
|
||||
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);
|
||||
post.setHeaders(entryHeaders);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
String filename = req.getFilename("entryfile" + i);
|
||||
if ( (filename != null) && (filename.trim().length() > 0) ) {
|
||||
Hashtable params = req.getParams("entryfile" + i);
|
||||
String type = "application/octet-stream";
|
||||
for (Iterator iter = params.keySet().iterator(); iter.hasNext(); ) {
|
||||
String cur = (String)iter.next();
|
||||
if ("content-type".equalsIgnoreCase(cur)) {
|
||||
type = (String)params.get(cur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
post.addAttachment(filename.trim(), req.getInputStream("entryfile" + i), type);
|
||||
}
|
||||
}
|
||||
|
||||
post.renderPreview(out);
|
||||
%><hr /><span class="b_postConfirm"><form action="post.jsp" method="POST">
|
||||
Please confirm that the above is ok<% if (BlogManager.instance().authorizeRemote(user)) { %>, and select what additional archives you
|
||||
want the post transmitted to. Otherwise, just hit your browser's back arrow and
|
||||
make changes.
|
||||
<select class="b_postConfirm" name="archive">
|
||||
<option name="">-None-</option>
|
||||
<%
|
||||
PetNameDB db = user.getPetNameDB();
|
||||
TreeSet names = new TreeSet();
|
||||
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
PetName pn = db.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");
|
||||
}
|
||||
%>
|
||||
Blog entry <a href="<%=HTMLRenderer.getPageURL(user.getBlog(), null, entry.getEntryId(), -1, -1, user.getShowExpanded(), user.getShowImages())%>">posted</a>!
|
||||
<% } else { %>
|
||||
There was an error posting... dunno what it was...
|
||||
<% }
|
||||
}
|
||||
} else { %><form action="post.jsp" method="POST" enctype="multipart/form-data">
|
||||
Post subject: <input type="text" size="80" name="entrysubject" /><br />
|
||||
Post tags: <input type="text" size="20" name="entrytags" /><br />
|
||||
Post content (in raw SML, no headers):<br />
|
||||
<textarea rows="6" cols="80" name="entrytext"></textarea><br />
|
||||
<b>SML cheatsheet:</b><br /><textarea rows="6" cols="80" readonly="true">
|
||||
</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">
|
||||
<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>
|
||||
@@ -81,32 +144,29 @@ Post content (in raw SML, no headers):<br />
|
||||
* [blog name="name" bloghash="base64hash" blogtag="tag"]description[/blog] = link to all posts in the blog with the specified tag
|
||||
* [blog name="name" blogtag="tag"]description[/blog] = link to all posts in all blogs with the specified tag
|
||||
* [link schema="eep" location="http://forum.i2p"]text[/link] = offer a link to an external resource (accessible with the given schema)
|
||||
* [archive name="name" description="they have good stuff" schema="eep" location="http://syndiemedia.i2p/archive/archive.txt"]foo![/archive] = offer an easy way to sync up with a new Syndie archive
|
||||
|
||||
SML headers are newline delimited key=value pairs. Example keys are:
|
||||
* bgcolor = background color of the post (e.g. bgcolor=#ffccaa or bgcolor=red)
|
||||
* bgimage = attachment number to place as the background image for the post (only shown if images are enabled) (e.g. bgimage=1)
|
||||
* textfont = font to put most text into
|
||||
</textarea><br />
|
||||
SML post headers:<br />
|
||||
<textarea rows="3" cols="80" name="entryheaders"></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="Post entry" /> <input type="reset" value="Cancel" />
|
||||
<% } %>
|
||||
</td></tr>
|
||||
<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
|
||||
} // end of the 'logged in' section
|
||||
%></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
|
@@ -1,17 +1,19 @@
|
||||
<%@page import="net.i2p.data.Base64, net.i2p.syndie.web.*, net.i2p.syndie.sml.*, net.i2p.syndie.*" %>
|
||||
<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" >
|
||||
</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"))) ) {
|
||||
@@ -22,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>
|
||||
|
83
apps/syndie/jsp/remote.jsp
Normal file
@@ -0,0 +1,83 @@
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*, net.i2p.syndie.*, net.i2p.syndie.sml.*, java.util.*" %><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
%><jsp:useBean scope="session" class="net.i2p.syndie.web.RemoteArchiveBean" id="remote"
|
||||
/><jsp:useBean scope="session" class="net.i2p.syndie.User" id="user"
|
||||
/><jsp:useBean scope="session" class="net.i2p.syndie.data.TransparentArchiveIndex" id="archive"
|
||||
/><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>SyndieMedia remote</title>
|
||||
<link href="style.jsp" rel="stylesheet" type="text/css" >
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr class="b_toplogo"><td colspan="5" valign="top" align="left" class="b_toplogo"><jsp:include page="_toplogo.jsp" /></td></tr>
|
||||
<tr><td valign="top" align="left" rowspan="2" class="b_leftnav"><jsp:include page="_leftnav.jsp" /></td>
|
||||
<jsp:include page="_topnav.jsp" />
|
||||
<td valign="top" align="left" rowspan="2" class="b_rightnav"><jsp:include page="_rightnav.jsp" /></td></tr>
|
||||
<tr class="b_content"><td valign="top" align="left" colspan="3" class="b_content"><%
|
||||
if (!BlogManager.instance().authorizeRemote(user)) {
|
||||
%><span class="b_remoteMsgErr">Sorry, you are not allowed to access remote archives from here. Perhaps you should install Syndie yourself?</span><%
|
||||
} else { %><form action="remote.jsp" method="POST"><span class="b_remoteChooser"><span class="b_remoteChooserField">Import from:</span>
|
||||
<select class="b_remoteChooserNet" name="schema">
|
||||
<option value="web" <%=("web".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>I2P/TOR/Freenet</option>
|
||||
<option value="mnet" <%=("mnet".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>MNet</option>
|
||||
<option value="feedspace" <%=("feedspace".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>Feedspace</option>
|
||||
<option value="usenet" <%=("usenet".equals(request.getParameter("schema")) ? "selected=\"true\"" : "")%>>Usenet</option>
|
||||
</select>
|
||||
<span class="b_remoteChooserField">Proxy</span>
|
||||
<input class="b_remoteChooserHost" type="text" size="10" name="proxyhost" value="<%=BlogManager.instance().getDefaultProxyHost()%>" />
|
||||
<input class="b_remoteChooserPort" type="text" size="4" name="proxyport" value="<%=BlogManager.instance().getDefaultProxyPort()%>" /><br />
|
||||
<span class="b_remoteChooserField">Bookmarked archives:</span> <select class="b_remoteChooserPN" name="archivepetname"><option value="">Custom location</option><%
|
||||
for (Iterator iter = user.getPetNameDB().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)) {
|
||||
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)) {
|
||||
//remote.fetchSelectedEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, request.getParameterMap());
|
||||
} else if ("Fetch all new entries".equals(action)) {
|
||||
//remote.fetchAllEntries(user, request.getParameterMap());
|
||||
remote.fetchSelectedBulk(user, request.getParameterMap());
|
||||
} else if ("Post selected entries".equals(action)) {
|
||||
remote.postSelectedEntries(user, request.getParameterMap());
|
||||
}
|
||||
String msgs = remote.getStatus();
|
||||
if ( (msgs != null) && (msgs.length() > 0) ) { %><pre class="b_remoteProgress"><%=msgs%>
|
||||
<a class="b_remoteProgress" href="remote.jsp">Refresh</a></pre><br /><%
|
||||
}
|
||||
if (remote.getFetchIndexInProgress()) { %><span class="b_remoteProgress">Please wait while the index is being fetched
|
||||
from <%=remote.getRemoteLocation()%>.</span><%
|
||||
} else if (remote.getRemoteIndex() != null) {
|
||||
// remote index is NOT null!
|
||||
%><span class="b_remoteLocation"><%=remote.getRemoteLocation()%></span>
|
||||
<a class="b_remoteRefetch" href="remote.jsp?schema=<%=remote.getRemoteSchema()%>&location=<%=remote.getRemoteLocation()%><%
|
||||
if (remote.getProxyHost() != null && remote.getProxyPort() > 0) {
|
||||
%>&proxyhost=<%=remote.getProxyHost()%>&proxyport=<%=remote.getProxyPort()%><%
|
||||
} %>&action=Continue...">(refetch)</a>:<br />
|
||||
<%remote.renderDeltaForm(user, archive, out);%>
|
||||
<textarea class="b_remoteIndex" rows="5" cols="120"><%=remote.getRemoteIndex()%></textarea><%
|
||||
}
|
||||
}
|
||||
%>
|
||||
</td></form></tr>
|
||||
</table>
|
||||
</body>
|
7
apps/syndie/jsp/style.jsp
Normal file
@@ -0,0 +1,7 @@
|
||||
<%@page contentType="text/css; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.util.FileUtil" %>
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<%@include file="syndie.css" %>
|
||||
<%
|
||||
String content = FileUtil.readTextFile("./docs/syndie_standard.css", -1, true);
|
||||
if (content != null) out.write(content);
|
||||
%>
|
107
apps/syndie/jsp/syndie.css
Normal file
@@ -0,0 +1,107 @@
|
||||
body {
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
background-color : #EEEEEE;
|
||||
color: #000000;
|
||||
font-size: 12px;
|
||||
}
|
||||
.b_topnavUser {
|
||||
text-align: right;
|
||||
background-color: #CCCCDD;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
}
|
||||
.b_topnavHome {
|
||||
background-color: #CCCCDD;
|
||||
color: #000000;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
.b_topnav {
|
||||
background-color: #CCCCDD;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
}
|
||||
.b_content {
|
||||
border: 0px;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.s_summary_overall {
|
||||
border: 0px;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.s_detail_overall {
|
||||
border: 0px;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.s_detail_subject {
|
||||
font-size: 10px;
|
||||
text-align: left;
|
||||
background-color: #BBBBFF;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
.s_detail_meta {
|
||||
font-size: 10px;
|
||||
text-align: right;
|
||||
background-color: #BBBBFF;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.s_summary_subject {
|
||||
font-size: 10px;
|
||||
text-align: left;
|
||||
background-color: #BBBBFF;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
.s_summary_meta {
|
||||
font-size: 10px;
|
||||
text-align: right;
|
||||
background-color: #BBBBFF;
|
||||
border-spacing: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border-width: 0px;
|
||||
border: 0px;
|
||||
border-style: none;
|
||||
}
|
||||
.s_summary_summDetail {
|
||||
font-size: 10px;
|
||||
}
|
||||
.s_detail_summDetail {
|
||||
}
|
||||
.s_detail_summDetailBlog {
|
||||
}
|
||||
.s_detail_summDetailBlogLink {
|
||||
}
|
||||
td.s_detail_summDetail {
|
||||
background-color: #DDDDFF;
|
||||
}
|
||||
td.s_summary_summ {
|
||||
font-size: 10px;
|
||||
background-color: #DDDDFF;
|
||||
}
|
1
apps/syndie/jsp/syndie/index.jsp
Normal file
@@ -0,0 +1 @@
|
||||
<%response.sendRedirect("../index.jsp");%>
|
@@ -1,3 +1,4 @@
|
||||
<% request.setCharacterEncoding("UTF-8"); %>
|
||||
<%
|
||||
java.util.Map params = request.getParameterMap();
|
||||
response.setContentType(net.i2p.syndie.web.ArchiveViewerBean.getAttachmentContentType(params));
|
||||
|
@@ -1,16 +1,35 @@
|
||||
<%@page contentType="text/html" import="net.i2p.syndie.web.*" %>
|
||||
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="net.i2p.syndie.web.*, 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>
|
||||
<title>SyndieMedia metadata</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"><%
|
||||
ArchiveViewerBean.renderMetadata(request.getParameterMap(), out);
|
||||
if (user.getAuthenticated()) {
|
||||
if ("Authorize".equals(request.getParameter("action"))) {
|
||||
%><span class="b_metaStatus"><%=BlogManager.instance().authorizeRemoteAccess(user, request.getParameter("password"))%></span><%
|
||||
}
|
||||
if (!user.getAllowAccessRemote()) {
|
||||
if (user.getBlog().toBase64().equals(request.getParameter("blog"))) {
|
||||
%><hr /><form action="viewmetadata.jsp" method="POST">
|
||||
<input type="hidden" name="blog" value="<%=request.getParameter("blog")%>" />
|
||||
<span class="b_metaAuthorize">To access remote instances from this instance, please supply the Syndie administration password:</span>
|
||||
<input class="b_metaAuthorize" type="password" name="password" />
|
||||
<input class="b_metaAuthorizeSubmit" type="submit" name="action" value="Authorize" />
|
||||
</form><%
|
||||
}
|
||||
}
|
||||
}
|
||||
%></td></tr>
|
||||
</table>
|
||||
</body>
|
16
apps/syndie/jsp/viewtempattachment.jsp
Normal file
@@ -0,0 +1,16 @@
|
||||
<%@page import="net.i2p.syndie.web.ArchiveViewerBean" %><jsp:useBean
|
||||
scope="session" class="net.i2p.syndie.web.PostBean" id="post" /><%
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
String id = request.getParameter(ArchiveViewerBean.PARAM_ATTACHMENT);
|
||||
if (id != null) {
|
||||
try {
|
||||
int attachmentId = Integer.parseInt(id);
|
||||
if ( (attachmentId < 0) || (attachmentId >= post.getAttachmentCount()) ) {
|
||||
%>Attachment <%=attachmentId%> does not exist<%
|
||||
} else {
|
||||
response.setContentType(post.getContentType(attachmentId));
|
||||
post.writeAttachmentData(attachmentId, response.getOutputStream());
|
||||
}
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
%>
|