added rss2.0 support via rss.jsp

rss.jsp can in turn receive all the filters that index.jsp can - e.g. ?blog=blah or ?selector=group://foo,
and by default returns the latest 10 values (overridden with ?wanted=15).  If you want it to pull
with a user's blog's preferences (filters, groups, etc), you can specify ?login=user&password=password
This commit is contained in:
jrandom
2005-09-05 05:33:33 +00:00
committed by zzz
parent 3bb445ff40
commit 61b8e3598b
7 changed files with 453 additions and 8 deletions

View File

@ -184,6 +184,7 @@ public class BlogManager {
}
public String login(User user, String login, String pass) {
if ( (login == null) || (pass == null) ) return "Login not specified";
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()));

View File

@ -83,6 +83,15 @@ public class HTMLRenderer extends EventReceiverImpl {
render(user, archive, entry, entry.getEntry().getText(), out, cutBody, showImages);
}
public void render(User user, Archive archive, EntryContainer entry, String rawSML, Writer out, boolean cutBody, boolean showImages) throws IOException {
prepare(user, archive, entry, rawSML, out, cutBody, showImages);
_out.write(_preBodyBuffer.toString());
_out.write(_bodyBuffer.toString());
_out.write(_postBodyBuffer.toString());
//int len = _preBodyBuffer.length() + _bodyBuffer.length() + _postBodyBuffer.length();
//System.out.println("Wrote " + len);
}
protected void prepare(User user, Archive archive, EntryContainer entry, String rawSML, Writer out, boolean cutBody, boolean showImages) throws IOException {
_user = user;
_archive = archive;
_entry = entry;
@ -100,11 +109,6 @@ public class HTMLRenderer extends EventReceiverImpl {
_cutReached = false;
_cutSize = 1024;
_parser.parse(rawSML, this);
_out.write(_preBodyBuffer.toString());
_out.write(_bodyBuffer.toString());
_out.write(_postBodyBuffer.toString());
//int len = _preBodyBuffer.length() + _bodyBuffer.length() + _postBodyBuffer.length();
//System.out.println("Wrote " + len);
}
public void receivePlain(String text) {
@ -787,8 +791,30 @@ public class HTMLRenderer extends EventReceiverImpl {
return sanitizeString(str);
}
private String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : false); }
private String getEntryURL(boolean showImages) {
public static final String sanitizeXML(String orig) {
if (orig.indexOf('&') < 0) return orig;
StringBuffer rv = new StringBuffer(orig.length()+32);
for (int i = 0; i < orig.length(); i++) {
if (orig.charAt(i) == '&')
rv.append("&amp;");
else
rv.append(orig.charAt(i));
}
return rv.toString();
}
public static final String sanitizeXML(StringBuffer orig) {
if (orig.indexOf("&") < 0) return orig.toString();
for (int i = 0; i < orig.length(); i++) {
if (orig.charAt(i) == '&') {
orig = orig.replace(i, i+1, "&amp;");
i += "&amp;".length();
}
}
return orig.toString();
}
protected String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : false); }
protected String getEntryURL(boolean showImages) {
if (_entry == null) return "unknown";
return "index.jsp?" + ArchiveViewerBean.PARAM_BLOG + "=" +
Base64.encode(_entry.getURI().getKeyHash().getData()) +

View File

@ -0,0 +1,305 @@
package net.i2p.syndie.sml;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import net.i2p.data.*;
import net.i2p.syndie.*;
import net.i2p.syndie.data.*;
/**
*
*/
public class RSSRenderer extends HTMLRenderer {
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("addaddress.jsp?schema=");
url.append(sanitizeURL(a.schema)).append("&location=");
url.append(sanitizeURL(a.location)).append("&name=");
url.append(sanitizeURL(a.name)).append("&protocol=");
url.append(sanitizeURL(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 + "]");
}
}

View File

@ -489,7 +489,7 @@ 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);

View File

@ -0,0 +1,94 @@
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.*;
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();
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();
}
}

View File

@ -4,6 +4,16 @@
<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%">

View File

@ -9,6 +9,11 @@
<servlet-class>net.i2p.syndie.web.ArchiveServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>net.i2p.syndie.web.RSSServlet</servlet-name>
<servlet-class>net.i2p.syndie.web.RSSServlet</servlet-class>
</servlet>
<!-- precompiled servlets -->
<servlet-mapping>
@ -19,6 +24,10 @@
<servlet-name>net.i2p.syndie.web.ArchiveServlet</servlet-name>
<url-pattern>/archive/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>net.i2p.syndie.web.RSSServlet</servlet-name>
<url-pattern>/rss.jsp</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>