diff --git a/apps/syndie/java/src/net/i2p/syndie/data/BlogInfo.java b/apps/syndie/java/src/net/i2p/syndie/data/BlogInfo.java
index 6ad973cd06..41839f227a 100644
--- a/apps/syndie/java/src/net/i2p/syndie/data/BlogInfo.java
+++ b/apps/syndie/java/src/net/i2p/syndie/data/BlogInfo.java
@@ -57,6 +57,7 @@ public class BlogInfo {
public static final String DESCRIPTION = "Description";
public static final String CONTACT_URL = "ContactURL";
public static final String EDITION = "Edition";
+ public static final String SUMMARY_ENTRY_ID = "SummaryEntryId";
public void load(InputStream in) throws IOException {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
diff --git a/apps/syndie/java/src/net/i2p/syndie/data/BlogInfoData.java b/apps/syndie/java/src/net/i2p/syndie/data/BlogInfoData.java
new file mode 100644
index 0000000000..b1aeb60e01
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/data/BlogInfoData.java
@@ -0,0 +1,127 @@
+package net.i2p.syndie.data;
+
+import java.io.*;
+import java.util.*;
+import net.i2p.client.naming.PetName;
+import net.i2p.data.DataHelper;
+
+/**
+ * Contain the current supplementary data for rendering a blog, as opposed to
+ * just verifying and rendering a post.
+ */
+public class BlogInfoData {
+ private BlogURI _dataEntryId;
+ /** list of List of PetName instances that the blog refers to */
+ private List _referenceGroups;
+ /** customized style config */
+ private Properties _styleOverrides;
+ /** the blog's logo */
+ private Attachment _logo;
+ private List _otherAttachments;
+
+ public static final String ATTACHMENT_LOGO = "logo.png";
+ public static final String ATTACHMENT_REFERENCE_GROUPS = "groups.txt";
+ public static final String ATTACHMENT_STYLE_OVERRIDE = "style.cfg";
+ /** identifies a post as being a blog info data, not a content bearing post */
+ public static final String TAG = "BlogInfoData";
+
+ public BlogInfoData() {}
+
+ public BlogURI getEntryId() { return _dataEntryId; }
+ public boolean isLogoSpecified() { return _logo != null; }
+ public Attachment getLogo() { return _logo; }
+ public boolean isStyleSpecified() { return _styleOverrides != null; }
+ public Properties getStyleOverrides() { return _styleOverrides; }
+ public int getReferenceGroupCount() { return _referenceGroups != null ? _referenceGroups.size() : 0; }
+ /** list of PetName elements to be included in the list */
+ public List getReferenceGroup(int groupNum) { return (List)_referenceGroups.get(groupNum); }
+ public int getOtherAttachmentCount() { return _otherAttachments != null ? _otherAttachments.size() : 0; }
+ public Attachment getOtherAttachment(int num) { return (Attachment)_otherAttachments.get(num); }
+ public Attachment getOtherAttachment(String name) {
+ for (int i = 0; i < _otherAttachments.size(); i++) {
+ Attachment a = (Attachment)_otherAttachments.get(i);
+ if (a.getName().equals(name))
+ return a;
+ }
+ return null;
+ }
+
+ public void writeLogo(OutputStream out) throws IOException {
+ InputStream in = null;
+ try {
+ in = _logo.getDataStream();
+ byte buf[] = new byte[4096];
+ int read = 0;
+ while ( (read = in.read(buf)) != -1)
+ out.write(buf, 0, read);
+ } finally {
+ if (in != null) try { in.close(); } catch (IOException ioe) {}
+ }
+ }
+
+
+ public void load(EntryContainer entry) throws IOException {
+ _dataEntryId = entry.getURI();
+ Attachment attachments[] = entry.getAttachments();
+ for (int i = 0; i < attachments.length; i++) {
+ if (ATTACHMENT_LOGO.equals(attachments[i].getName())) {
+ _logo = attachments[i];
+ } else if (ATTACHMENT_REFERENCE_GROUPS.equals(attachments[i].getName())) {
+ readReferenceGroups(attachments[i]);
+ } else if (ATTACHMENT_STYLE_OVERRIDE.equals(attachments[i].getName())) {
+ readStyleOverride(attachments[i]);
+ } else {
+ if (_otherAttachments == null)
+ _otherAttachments = new ArrayList();
+ _otherAttachments.add(attachments[i]);
+ }
+ }
+ }
+
+ private void readReferenceGroups(Attachment att) throws IOException {
+ InputStream in = null;
+ try {
+ in = att.getDataStream();
+ StringBuffer line = new StringBuffer(128);
+ List groups = new ArrayList();
+ String prevGroup = null;
+ List defaultGroup = new ArrayList();
+ while (true) {
+ boolean ok = DataHelper.readLine(in, line);
+ if (line.length() > 0) {
+ PetName pn = new PetName(line.toString().trim());
+ if (pn.getGroupCount() <= 0) {
+ defaultGroup.add(pn);
+ } else if (pn.getGroup(0).equals(prevGroup)) {
+ List curGroup = (List)groups.get(groups.size()-1);
+ curGroup.add(pn);
+ } else {
+ List curGroup = new ArrayList();
+ curGroup.add(pn);
+ groups.add(curGroup);
+ prevGroup = pn.getGroup(0);
+ }
+ }
+ if (!ok)
+ break;
+ }
+ if (defaultGroup.size() > 0)
+ groups.add(defaultGroup);
+ _referenceGroups = groups;
+ } finally {
+ if (in != null) try { in.close(); } catch (IOException ioe) {}
+ }
+ }
+
+ private void readStyleOverride(Attachment att) throws IOException {
+ InputStream in = null;
+ try {
+ in = att.getDataStream();
+ Properties props = new Properties();
+ DataHelper.loadProps(props, in);
+ _styleOverrides = props;
+ } finally {
+ if (in != null) try { in.close(); } catch (IOException ioe) {}
+ }
+ }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/data/EntryContainer.java b/apps/syndie/java/src/net/i2p/syndie/data/EntryContainer.java
index d41a450047..a03271e9ac 100644
--- a/apps/syndie/java/src/net/i2p/syndie/data/EntryContainer.java
+++ b/apps/syndie/java/src/net/i2p/syndie/data/EntryContainer.java
@@ -59,7 +59,10 @@ public class EntryContainer {
public EntryContainer(BlogURI uri, String tags[], byte smlData[]) {
this();
_entryURI = uri;
- _entryData = new Entry(DataHelper.getUTF8(smlData));
+ if ( (smlData == null) || (smlData.length <= 0) )
+ _entryData = new Entry(null);
+ else
+ _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++)
@@ -203,10 +206,13 @@ public class EntryContainer {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
ZipEntry ze = new ZipEntry(ZIP_ENTRY);
- byte data[] = DataHelper.getUTF8(_entryData.getText());
+ byte data[] = null;
+ if (_entryData.getText() != null)
+ data = DataHelper.getUTF8(_entryData.getText());
ze.setTime(0);
out.putNextEntry(ze);
- out.write(data);
+ if (data != null)
+ out.write(data);
out.closeEntry();
for (int i = 0; (_attachments != null) && (i < _attachments.length); i++) {
ze = new ZipEntry(ZIP_ATTACHMENT_PREFIX + i + ZIP_ATTACHMENT_SUFFIX);
@@ -270,6 +276,9 @@ public class EntryContainer {
//System.out.println("Read entry [" + name + "] with size=" + entryData.length);
}
+ if (_entryData == null)
+ _entryData = new Entry(null);
+
_attachments = new Attachment[attachments.size()];
for (int i = 0; i < attachments.size(); i++) {
diff --git a/apps/syndie/java/src/net/i2p/syndie/sml/BlogRenderer.java b/apps/syndie/java/src/net/i2p/syndie/sml/BlogRenderer.java
new file mode 100644
index 0000000000..c03c96d1b6
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/sml/BlogRenderer.java
@@ -0,0 +1,189 @@
+package net.i2p.syndie.sml;
+
+import java.io.*;
+import java.util.*;
+import net.i2p.I2PAppContext;
+import net.i2p.client.naming.PetName;
+import net.i2p.data.*;
+import net.i2p.syndie.data.*;
+import net.i2p.syndie.web.*;
+
+/**
+ * Renders posts for display within the blog view
+ *
+ */
+public class BlogRenderer extends HTMLRenderer {
+ private BlogInfo _blog;
+ private BlogInfoData _data;
+ public BlogRenderer(I2PAppContext ctx, BlogInfo info, BlogInfoData data) {
+ super(ctx);
+ _blog = info;
+ _data = data;
+ }
+
+ public void receiveHeaderEnd() {
+ _preBodyBuffer.append("
\n");
+ _preBodyBuffer.append("\n");
+
+ _preBodyBuffer.append("
\n");
+ }
+
+ public void receiveEnd() {
+ _postBodyBuffer.append("
\n");
+ _postBodyBuffer.append("
\n");
+ int childCount = getChildCount(_archive.getIndex().getThreadedIndex().getNode(_entry.getURI()));
+ if ( (_cutReached || childCount > 0) && (_cutBody) ) {
+ _postBodyBuffer.append("
Read more ");
+ }
+ if (childCount > 0) {
+ _postBodyBuffer.append(childCount).append(" ");
+ if (childCount > 1)
+ _postBodyBuffer.append(" comments already, ");
+ else
+ _postBodyBuffer.append(" comment already, ");
+ }
+ _postBodyBuffer.append("
Leave a comment\n");
+ _postBodyBuffer.append("
\n");
+ _postBodyBuffer.append("
\n\n");
+ }
+ private int getChildCount(ThreadNode node) {
+ int nodes = 0;
+ for (int i = 0; i < node.getChildCount(); i++) {
+ nodes++;
+ nodes += getChildCount(node.getChild(i));
+ }
+ return nodes;
+ }
+
+ private String getAuthor() {
+ PetName pn = null;
+ if ( (_entry != null) && (_user != null) )
+ pn = _user.getPetNameDB().getByLocation(_entry.getURI().getKeyHash().toBase64());
+ if (pn != null)
+ return pn.getName();
+ BlogInfo info = null;
+ if (_entry != null) {
+ info = _archive.getBlogInfo(_entry.getURI());
+ if (info != null) {
+ String str = info.getProperty(BlogInfo.NAME);
+ if (str != null)
+ return str;
+ }
+ return _entry.getURI().getKeyHash().toBase64().substring(0,6);
+ } else {
+ return "No name?";
+ }
+ }
+
+ private void displayTag(StringBuffer buf, BlogInfoData data, String tag) {
+ //buf.append("");
+ if ( (tag == null) || ("[none]".equals(tag) ) )
+ return;
+ buf.append("
");
+ //buf.append("");
+ buf.append(" ");
+ }
+
+ public String getMetadataURL(Hash blog) { return ThreadedHTMLRenderer.buildProfileURL(blog); }
+ private String getTagIconURL(String tag) {
+ return "viewicon.jsp?tag=" + Base64.encode(tag) + "&" +
+ ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64();
+ }
+
+ private String getReplyURL() {
+ String subject = (String)_headers.get(HEADER_SUBJECT);
+ if (subject != null) {
+ if (!subject.startsWith("re:"))
+ subject = "re: " + subject;
+ } else {
+ subject = "re: ";
+ }
+ return "post.jsp?" + PostServlet.PARAM_PARENT + "="
+ + Base64.encode(_entry.getURI().getKeyHash().toBase64() + "/" + _entry.getURI().getEntryId()) + "&"
+ + PostServlet.PARAM_SUBJECT + "=" + sanitizeTagParam(subject) + "&";
+ }
+
+ protected String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : true); }
+ protected String getEntryURL(boolean showImages) {
+ if (_entry == null) return "unknown";
+ return "blog.jsp?"
+ + ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64() + "&"
+ + ViewBlogServlet.PARAM_ENTRY + "="
+ + Base64.encode(_entry.getURI().getKeyHash().getData()) + '/' + _entry.getURI().getEntryId();
+ }
+
+ protected String getAttachmentURLBase() {
+ return "invalid";
+ }
+
+ protected String getAttachmentURL(int id) {
+ if (_entry == null) return "unknown";
+ return "blog.jsp?"
+ + ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64() + "&"
+ + ViewBlogServlet.PARAM_ATTACHMENT + "="
+ + Base64.encode(_entry.getURI().getKeyHash().getData()) + "/"
+ + _entry.getURI().getEntryId() + "/"
+ + id;
+ }
+
+ public String getPageURL(String entry) {
+ StringBuffer buf = new StringBuffer(128);
+ buf.append("blog.jsp?");
+ buf.append(ViewBlogServlet.PARAM_BLOG).append(_blog.getKey().calculateHash().toBase64()).append("&");
+
+ if (entry != null) {
+ if (entry.startsWith("entry://"))
+ entry = entry.substring("entry://".length());
+ else if (entry.startsWith("blog://"))
+ entry = entry.substring("blog://".length());
+ int split = entry.indexOf('/');
+ if (split > 0) {
+ buf.append(ViewBlogServlet.PARAM_ENTRY).append("=");
+ buf.append(sanitizeTagParam(entry.substring(0, split))).append('/');
+ buf.append(sanitizeTagParam(entry.substring(split+1))).append("&");
+ }
+ }
+ return buf.toString();
+ }
+ public String getPageURL(Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
+ StringBuffer buf = new StringBuffer(128);
+ buf.append("blog.jsp?");
+ buf.append(ViewBlogServlet.PARAM_BLOG).append("=");
+ buf.append(_blog.getKey().calculateHash().toBase64()).append("&");
+
+ if ( (blog != null) && (entryId > 0) ) {
+ buf.append(ViewBlogServlet.PARAM_ENTRY).append("=");
+ buf.append(blog.toBase64()).append('/');
+ buf.append(entryId).append("&");
+ }
+ if (tag != null)
+ buf.append(ViewBlogServlet.PARAM_TAG).append('=').append(sanitizeTagParam(tag)).append("&");
+ if ( (pageNum >= 0) && (numPerPage > 0) )
+ buf.append(ViewBlogServlet.PARAM_OFFSET).append('=').append(pageNum*numPerPage).append("&");
+ return buf.toString();
+ }
+}
\ No newline at end of file
diff --git a/apps/syndie/java/src/net/i2p/syndie/sml/EventReceiverImpl.java b/apps/syndie/java/src/net/i2p/syndie/sml/EventReceiverImpl.java
index 399b01e921..854882aa95 100644
--- a/apps/syndie/java/src/net/i2p/syndie/sml/EventReceiverImpl.java
+++ b/apps/syndie/java/src/net/i2p/syndie/sml/EventReceiverImpl.java
@@ -8,7 +8,7 @@ import net.i2p.util.Log;
*
*/
public class EventReceiverImpl implements SMLParser.EventReceiver {
- private I2PAppContext _context;
+ protected I2PAppContext _context;
private Log _log;
public EventReceiverImpl(I2PAppContext ctx) {
diff --git a/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java b/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java
index 16a10d62c9..3174f404fd 100644
--- a/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java
+++ b/apps/syndie/java/src/net/i2p/syndie/sml/HTMLRenderer.java
@@ -1017,10 +1017,10 @@ public class HTMLRenderer extends EventReceiverImpl {
_entry.getURI().getEntryId();
}
- protected String getAttachmentURLBase() { return "viewattachment.jsp"; }
+ protected String getAttachmentURLBase() { return "viewattachment.jsp?"; }
protected String getAttachmentURL(int id) {
if (_entry == null) return "unknown";
- return getAttachmentURLBase() + "?" +
+ return getAttachmentURLBase() +
ArchiveViewerBean.PARAM_BLOG + "=" +
Base64.encode(_entry.getURI().getKeyHash().getData()) +
"&" + ArchiveViewerBean.PARAM_ENTRY + "=" + _entry.getURI().getEntryId() +
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ArchiveViewerBean.java b/apps/syndie/java/src/net/i2p/syndie/web/ArchiveViewerBean.java
index 66932e01bb..19af7e9a4d 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/ArchiveViewerBean.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/ArchiveViewerBean.java
@@ -596,9 +596,11 @@ public class ArchiveViewerBean {
}
public static void renderAttachment(Map parameters, OutputStream out) throws IOException {
- Attachment a = getAttachment(parameters);
+ renderAttachment(getAttachment(parameters), out);
+ }
+ public static void renderAttachment(Attachment a, OutputStream out) throws IOException {
if (a == null) {
- renderInvalidAttachment(parameters, out);
+ renderInvalidAttachment(out);
} else {
InputStream data = a.getDataStream();
byte buf[] = new byte[1024];
@@ -610,17 +612,21 @@ public class ArchiveViewerBean {
}
public static final String getAttachmentContentType(Map parameters) {
- Attachment a = getAttachment(parameters);
- if (a == null)
+ return getAttachmentContentType(getAttachment(parameters));
+ }
+ public static final String getAttachmentContentType(Attachment attachment) {
+ if (attachment == null)
return "text/html";
- String mime = a.getMimeType();
+ String mime = attachment.getMimeType();
if ( (mime != null) && ((mime.startsWith("image/") || mime.startsWith("text/plain"))) )
return mime;
return "application/octet-stream";
}
public static final boolean getAttachmentShouldShowInline(Map parameters) {
- Attachment a = getAttachment(parameters);
+ return getAttachmentShouldShowInline(getAttachment(parameters));
+ }
+ public static final boolean getAttachmentShouldShowInline(Attachment a) {
if (a == null)
return true;
String mime = a.getMimeType();
@@ -631,7 +637,9 @@ public class ArchiveViewerBean {
}
public static final int getAttachmentContentLength(Map parameters) {
- Attachment a = getAttachment(parameters);
+ return getAttachmentContentLength(getAttachment(parameters));
+ }
+ public static final int getAttachmentContentLength(Attachment a) {
if (a != null)
return a.getDataLength();
else
@@ -639,7 +647,9 @@ public class ArchiveViewerBean {
}
public static final String getAttachmentFilename(Map parameters) {
- Attachment a = getAttachment(parameters);
+ return getAttachmentFilename(getAttachment(parameters));
+ }
+ public static final String getAttachmentFilename(Attachment a) {
if (a != null)
return a.getName();
else
@@ -667,7 +677,7 @@ public class ArchiveViewerBean {
return null;
}
- private static void renderInvalidAttachment(Map parameters, OutputStream out) throws IOException {
+ private static void renderInvalidAttachment(OutputStream out) throws IOException {
out.write(DataHelper.getUTF8("No such entry, or no such attachment"));
}
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigBean.java b/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigBean.java
new file mode 100644
index 0000000000..d5ecd1c2dd
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigBean.java
@@ -0,0 +1,270 @@
+package net.i2p.syndie.web;
+
+import java.io.*;
+import java.util.*;
+import net.i2p.I2PAppContext;
+import net.i2p.client.naming.PetName;
+import net.i2p.data.DataHelper;
+import net.i2p.syndie.*;
+import net.i2p.syndie.data.*;
+import net.i2p.util.Log;
+
+/**
+ *
+ */
+public class BlogConfigBean {
+ private I2PAppContext _context;
+ private Log _log;
+ private User _user;
+ private String _title;
+ private String _description;
+ private String _contactInfo;
+ /** list of list of PetNames */
+ private List _groups;
+ private Properties _styleOverrides;
+ private File _logo;
+ private boolean _loaded;
+ private boolean _updated;
+
+ public BlogConfigBean() {
+ _context = I2PAppContext.getGlobalContext();
+ _log = _context.logManager().getLog(BlogConfigBean.class);
+ _groups = new ArrayList();
+ _styleOverrides = new Properties();
+ }
+
+ public User getUser() { return _user; }
+ public void setUser(User user) {
+ _user = user;
+ _title = null;
+ _description = null;
+ _contactInfo = null;
+ _groups.clear();
+ _styleOverrides.clear();
+ if (_logo != null)
+ _logo.delete();
+ _logo = null;
+ _loaded = false;
+ _updated = false;
+ load();
+ }
+ public String getTitle() { return _title; }
+ public void setTitle(String title) {
+ _title = title;
+ _updated = true;
+ }
+ public String getDescription() { return _description; }
+ public void setDescription(String desc) {
+ _description = desc;
+ _updated = true;
+ }
+ public String getContactInfo() { return _contactInfo; }
+ public void setContactInfo(String info) {
+ _contactInfo = info;
+ _updated = true;
+ }
+ public int getGroupCount() { return _groups.size(); }
+ /** gets the actual modifiable list of PetName instances */
+ public List getGroup(int i) { return (List)_groups.get(i); }
+ /** gets the actual modifiable list of PetName instances */
+ public List getGroup(String name) {
+ for (int i = 0; i < _groups.size(); i++) {
+ List grp = (List)_groups.get(i);
+ if (grp.size() > 0) {
+ PetName pn = (PetName)grp.get(0);
+ if ( (pn.getGroupCount() == 0) && ( (name == null) || (name.length() <= 0) ) )
+ return grp;
+ String curGroup = pn.getGroup(0);
+ if (curGroup.equals(name))
+ return grp;
+ }
+ }
+ return null;
+ }
+ /** adds the given element to the appropriate group (creating a new one if necessary) */
+ public void add(PetName pn) {
+ String groupName = null;
+ if (pn.getGroupCount() > 0)
+ groupName = pn.getGroup(0);
+ List group = getGroup(groupName);
+ if (group == null) {
+ group = new ArrayList(4);
+ group.add(pn);
+ _groups.add(group);
+ } else {
+ group.add(pn);
+ }
+ }
+ public void remove(PetName pn) {
+ String groupName = null;
+ if (pn.getGroupCount() > 0)
+ groupName = pn.getGroup(0);
+ List group = getGroup(groupName);
+ if (group != null) {
+ group.remove(pn);
+ if (group.size() <= 0)
+ _groups.remove(group);
+ }
+ }
+ public void remove(String name) {
+ for (int i = 0; i < getGroupCount(); i++) {
+ List group = getGroup(i);
+ for (int j = 0; j < group.size(); j++) {
+ PetName pn = (PetName)group.get(j);
+ if (pn.getName().equals(name)) {
+ group.remove(j);
+ if (group.size() <= 0)
+ _groups.remove(group);
+ return;
+ }
+ }
+ }
+ }
+ /** take note that the groups have been updated in some way (reordered, etc) */
+ public void groupsUpdated() { _updated = true; }
+ public String getStyleOverride(String prop) { return _styleOverrides.getProperty(prop); }
+ public void setStyleOverride(String prop, String val) {
+ _styleOverrides.setProperty(prop, val);
+ _updated = true;
+ }
+ public void unsetStyleOverride(String prop) {
+ _styleOverrides.remove(prop);
+ _updated = true;
+ }
+ public File getLogo() { return _logo; }
+ public void setLogo(File logo) {
+ if ( (logo != null) && (logo.length() > 128*1024) ) {
+ _log.error("Refusing a logo more than 128KB");
+ return;
+ }
+ _logo = logo;
+ _updated = true;
+ }
+ public boolean hasPendingChanges() { return _updated; }
+
+ private void load() {
+ Archive archive = BlogManager.instance().getArchive();
+ BlogInfo info = archive.getBlogInfo(_user.getBlog());
+ if (info != null) {
+ _title = info.getProperty(BlogInfo.NAME);
+ _description = info.getProperty(BlogInfo.DESCRIPTION);
+ _contactInfo = info.getProperty(BlogInfo.CONTACT_URL);
+ String id = info.getProperty(BlogInfo.SUMMARY_ENTRY_ID);
+ if (id != null) {
+ BlogURI uri = new BlogURI(id);
+ EntryContainer entry = archive.getEntry(uri);
+ if (entry != null) {
+ BlogInfoData data = new BlogInfoData();
+ try {
+ data.load(entry);
+ if (data.isLogoSpecified()) {
+ File logo = File.createTempFile("logo", ".png", BlogManager.instance().getTempDir());
+ FileOutputStream os = null;
+ try {
+ os = new FileOutputStream(logo);
+ data.writeLogo(os);
+ _logo = logo;
+ } finally {
+ if (os != null) try { os.close(); } catch (IOException ioe) {}
+ }
+ }
+ for (int i = 0; i < data.getReferenceGroupCount(); i++) {
+ List group = (List)data.getReferenceGroup(i);
+ for (int j = 0; j < group.size(); j++) {
+ PetName pn = (PetName)group.get(j);
+ add(pn);
+ }
+ }
+ _styleOverrides.putAll(data.getStyleOverrides());
+ } catch (IOException ioe) {
+ _log.warn("Unable to load the blog info data from " + uri, ioe);
+ }
+ }
+ }
+ }
+ _loaded = true;
+ }
+
+ public boolean publishChanges() throws IOException {
+ FileInputStream logo = null;
+ try {
+ if (_logo != null)
+ logo = new FileInputStream(_logo);
+ InputStream styleStream = createStyleStream();
+ InputStream groupStream = createGroupStream();
+
+ String tags = BlogInfoData.TAG;
+ String subject = "n/a";
+ String headers = "";
+ String sml = "";
+ List filenames = new ArrayList();
+ List filestreams = new ArrayList();
+ List filetypes = new ArrayList();
+ if (logo != null) {
+ filenames.add(BlogInfoData.ATTACHMENT_LOGO);
+ filestreams.add(logo);
+ filetypes.add("image/png");
+ }
+ filenames.add(BlogInfoData.ATTACHMENT_STYLE_OVERRIDE);
+ filestreams.add(styleStream);
+ filetypes.add("text/plain");
+ filenames.add(BlogInfoData.ATTACHMENT_REFERENCE_GROUPS);
+ filestreams.add(groupStream);
+ filetypes.add("text/plain");
+
+ BlogURI uri = BlogManager.instance().createBlogEntry(_user, subject, tags, headers, sml,
+ filenames, filestreams, filetypes);
+ if (uri != null) {
+ Archive archive = BlogManager.instance().getArchive();
+ BlogInfo info = archive.getBlogInfo(_user.getBlog());
+ if (info != null) {
+ String props[] = info.getProperties();
+ Properties opts = new Properties();
+ for (int i = 0; i < props.length; i++) {
+ if (!props[i].equals(BlogInfo.SUMMARY_ENTRY_ID))
+ opts.setProperty(props[i], info.getProperty(props[i]));
+ }
+ opts.setProperty(BlogInfo.SUMMARY_ENTRY_ID, uri.toString());
+ boolean updated = BlogManager.instance().updateMetadata(_user, _user.getBlog(), opts);
+ if (updated) {
+ // ok great, published locally, though should we push it to others?
+ _log.info("Blog summary updated for " + _user + " in " + uri.toString());
+ return true;
+ }
+ } else {
+ _log.error("Info is not known for " + _user.getBlog().toBase64());
+ return false;
+ }
+ } else {
+ _log.error("Error creating the summary entry");
+ return false;
+ }
+ } finally {
+ if (logo != null) try { logo.close(); } catch (IOException ioe) {}
+ // the other streams are in-memory, drop with the scope
+ }
+ return false;
+ }
+ private InputStream createStyleStream() throws IOException {
+ StringBuffer buf = new StringBuffer(1024);
+ if (_styleOverrides != null) {
+ for (Iterator iter = _styleOverrides.keySet().iterator(); iter.hasNext(); ) {
+ String key = (String)iter.next();
+ String val = _styleOverrides.getProperty(key);
+ buf.append(key).append('=').append(val).append('\n');
+ }
+ }
+ return new ByteArrayInputStream(DataHelper.getUTF8(buf));
+ }
+ private InputStream createGroupStream() throws IOException {
+ StringBuffer buf = new StringBuffer(1024);
+ for (int i = 0; i < _groups.size(); i++) {
+ List group = (List)_groups.get(i);
+ for (int j = 0; j < group.size(); j++) {
+ PetName pn = (PetName)group.get(j);
+ buf.append(pn.toString()).append('\n');
+ }
+ }
+ return new ByteArrayInputStream(DataHelper.getUTF8(buf));
+ }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigServlet.java
new file mode 100644
index 0000000000..117bf9161e
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/web/BlogConfigServlet.java
@@ -0,0 +1,231 @@
+package net.i2p.syndie.web;
+
+import java.io.*;
+import java.util.*;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletException;
+
+import net.i2p.I2PAppContext;
+import net.i2p.client.naming.*;
+import net.i2p.data.*;
+import net.i2p.syndie.*;
+import net.i2p.syndie.data.*;
+import net.i2p.syndie.sml.*;
+
+/**
+ * Display our blog config, and let us edit it through several screens
+ *
+ */
+public class BlogConfigServlet extends BaseServlet {
+ private static final String ATTR_CONFIG_BEAN = "__blogConfigBean";
+ public static final String PARAM_CONFIG_SCREEN = "screen";
+ public static final String SCREEN_GENERAL = "general";
+ public static final String SCREEN_REFERENCES = "references";
+ protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
+ int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
+ if ( (user == null) || (!user.getAuthenticated() && !BlogManager.instance().isSingleUser())) {
+ out.write("You must be logged in to edit your profile");
+ return;
+ }
+ BlogConfigBean bean = (BlogConfigBean)req.getSession().getAttribute(ATTR_CONFIG_BEAN);
+ if (bean == null) {
+ bean = new BlogConfigBean();
+ bean.setUser(user);
+ }
+
+ // handle actions here...
+ // on done handling
+
+ String screen = req.getParameter(PARAM_CONFIG_SCREEN);
+ if (screen == null)
+ screen = SCREEN_GENERAL;
+ out.write("todo: Display screen " + screen);
+ /*
+ if (SCREEN_REFERENCES.equals(screen)) {
+ displayReferencesScreen(req, out, bean);
+ } else {
+ displayGeneralScreen(req, out, bean);
+ }
+ */
+ }
+ /*
+ private void renderMyProfile(User user, String baseURI, PrintWriter out, Archive archive) throws IOException {
+ BlogInfo info = archive.getBlogInfo(user.getBlog());
+ if (info == null)
+ return;
+
+ out.write("\n");
+ out.write("\n");
+ }
+
+ private void renderProfile(User user, String baseURI, PrintWriter out, Hash author, Archive archive) throws IOException {
+ out.write("Profile for ");
+ PetName pn = user.getPetNameDB().getByLocation(author.toBase64());
+ String name = null;
+ BlogInfo info = archive.getBlogInfo(author);
+ if (pn != null) {
+ out.write(pn.getName());
+ name = null;
+ if (info != null)
+ name = info.getProperty(BlogInfo.NAME);
+
+ if ( (name == null) || (name.trim().length() <= 0) )
+ name = author.toBase64().substring(0, 6);
+
+ out.write(" (" + name + ")");
+ } else {
+ if (info != null)
+ name = info.getProperty(BlogInfo.NAME);
+
+ if ( (name == null) || (name.trim().length() <= 0) )
+ name = author.toBase64().substring(0, 6);
+ out.write(name);
+ }
+ out.write("");
+ if (info != null)
+ out.write(" [edition " + info.getEdition() + "]");
+ out.write(" \n");
+ out.write("View their blog or ");
+ out.write("threads they have participated in\n");
+ out.write(" |
\n");
+
+ out.write("
|
\n");
+ if (pn == null) {
+ out.write("Not currently bookmarked. Add them to your ");
+ String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("favorites or ");
+ out.write("ignored ");
+ out.write(" |
\n");
+ } else if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) {
+ out.write("Currently ignored - threads they create are hidden. |
\n");
+ String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_IGNORE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Unignore " + pn.getName() + " |
\n");
+ String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Forget about " + pn.getName() + " entirely |
\n");
+ } else if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) {
+ out.write("Currently marked as a favorite author - threads they participate in " +
+ "are highlighted. |
\n");
+ String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_FAVORITE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Remove " + pn.getName() + " from the list of favorite authors |
\n");
+ String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Ignore the author |
");
+ String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Forget about " + pn.getName() + " entirely |
\n");
+ } else {
+ out.write("Currently bookmarked. Add them to your ");
+ String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("favorites or ");
+ out.write("ignored list |
");
+ String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
+ baseURI, "", "", "", "", "", author.toBase64());
+ out.write("Forget about " + pn.getName() + " entirely |
\n");
+ }
+
+ if (info != null) {
+ String descr = info.getProperty(BlogInfo.DESCRIPTION);
+ if ( (descr != null) && (descr.trim().length() > 0) )
+ out.write("Account description: " + HTMLRenderer.sanitizeString(descr) + " |
\n");
+
+ String contactURL = info.getProperty(BlogInfo.CONTACT_URL);
+ if ( (contactURL != null) && (contactURL.trim().length() > 0) )
+ out.write("Contact information: "
+ + HTMLRenderer.sanitizeString(contactURL) + " |
\n");
+
+ String props[] = info.getProperties();
+ int altCount = 0;
+ if (props != null)
+ for (int i = 0; i < props.length; i++)
+ if (!BlogInfo.NAME.equals(props[i]) &&
+ !BlogInfo.DESCRIPTION.equals(props[i]) &&
+ !BlogInfo.EDITION.equals(props[i]) &&
+ !BlogInfo.OWNER_KEY.equals(props[i]) &&
+ !BlogInfo.POSTERS.equals(props[i]) &&
+ !BlogInfo.SIGNATURE.equals(props[i]) &&
+ !BlogInfo.CONTACT_URL.equals(props[i]))
+ altCount++;
+ if (altCount > 0) {
+ for (int i = 0; i < props.length; i++) {
+ if (!BlogInfo.NAME.equals(props[i]) &&
+ !BlogInfo.DESCRIPTION.equals(props[i]) &&
+ !BlogInfo.EDITION.equals(props[i]) &&
+ !BlogInfo.OWNER_KEY.equals(props[i]) &&
+ !BlogInfo.POSTERS.equals(props[i]) &&
+ !BlogInfo.SIGNATURE.equals(props[i]) &&
+ !BlogInfo.CONTACT_URL.equals(props[i])) {
+ out.write("");
+ out.write(HTMLRenderer.sanitizeString(props[i]) + ": "
+ + HTMLRenderer.sanitizeString(info.getProperty(props[i])));
+ out.write(" |
\n");
+ }
+ }
+ }
+ }
+ }
+ */
+
+ protected String getTitle() { return "Syndie :: Configure blog"; }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
index 67fe19171b..6fd9133c47 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
@@ -59,7 +59,7 @@ public class ProfileServlet extends BaseServlet {
out.write("