/* Freenet Plugin to run WikiApp.
*
* Copyright (C) 2010, 2011 Darrell Karbott
*
* This library 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.0 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks
*
* This file was developed as component of
* "fniki" (a wiki implementation running over Freenet).
*/
package fniki.freenet.plugin;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import freenet.pluginmanager.AccessDeniedPluginHTTPException;
import freenet.pluginmanager.FredPlugin;
import freenet.pluginmanager.FredPluginHTTP;
import freenet.pluginmanager.FredPluginThreadless;
import freenet.pluginmanager.NotFoundPluginHTTPException;
import freenet.pluginmanager.PluginHTTPException;
import freenet.pluginmanager.PluginRespirator;
import freenet.pluginmanager.RedirectPluginHTTPException;
import freenet.support.api.HTTPRequest;
import fniki.wiki.ArchiveManager;
import fniki.wiki.Query;
import fniki.wiki.Request;
import fniki.wiki.WikiApp;
import fniki.wiki.AccessDeniedException;
import fniki.wiki.NotFoundException;
import fniki.wiki.RedirectException;
import fniki.wiki.ChildContainerException;
public class Fniki implements FredPlugin, FredPluginHTTP, FredPluginThreadless {
private WikiApp mWikiApp;
public void terminate() {
System.err.println("terminating...");
}
public void runPlugin(PluginRespirator pr) {
try {
ArchiveManager archiveManager = new ArchiveManager();
// DCI: Parameter handling?
archiveManager.setFcpHost("127.0.0.1");
archiveManager.setFcpPort(9481);
archiveManager.setFmsHost("127.0.0.1");
archiveManager.setFmsPort(1119);
// YOU MUST SET THESE OR THE PLUGIN WON'T LOAD.
archiveManager.setPrivateSSK("FMS_PRIVATE_SSK");
archiveManager.setFmsId("FMS_ID");
archiveManager.setFmsGroup("biss.test000");
archiveManager.setBissName("testwiki");
String fproxyPrefix = "http://127.0.0.1:8888/";
boolean enableImages = true;
archiveManager.createEmptyArchive();
WikiApp wikiApp = new WikiApp(archiveManager);
final String containerPrefix = wikiApp.getString("container_prefix", null);
if (containerPrefix == null) {
throw new RuntimeException("Assertion Failure: container_prefix not set!");
}
wikiApp.setFproxyPrefix(fproxyPrefix);
wikiApp.setAllowImages(enableImages);
// IMPORTANT:
// HTTP POSTS will be rejected without any useful error message if your form
// doesn't contain a hidden field with the freenet per boot form password.
wikiApp.setFormPassword(pr.getNode().clientCore.formPassword);
mWikiApp = wikiApp;
} catch (IOException ioe) {
System.err.println("EPIC FAIL!");
ioe.printStackTrace();
}
}
private static class ServerPluginHTTPException extends PluginHTTPException {
private static final long serialVersionUID = -1;
public static final short code = 500; // Bad Request
public ServerPluginHTTPException(String errorMessage, String location) {
super(errorMessage, location);
}
}
private static class PluginQuery implements Query {
private final HTTPRequest mParent;
private final String mTitle;
private final String mAction;
private final String mSaveText;
private final String mSavePage;
PluginQuery(HTTPRequest parent, String path) {
mParent = parent;
String title = path;
if (parent.isParameterSet("title")) {
title = parent.getParam("title");
}
mTitle = title;
// DCI: validate title here
String action = "view";
if (parent.isParameterSet("action")) {
action = parent.getParam("action");
}
mAction = action;
// Handle multipart form parameters.
System.err.println("Dumping list of parts...");
String saveText = "";
String savePage = "";
try {
for (String part : parent.getParts()) {
if (part.equals("savetext")) {
// DCI: magic numbers
saveText = new String(parent.getPartAsBytesFailsafe(part, 64 * 1024), "utf-8");
continue;
}
if (part.equals("savepage")) {
savePage = new String(parent.getPartAsBytesFailsafe(part, 64 * 1024), "utf-8");
}
}
} catch (UnsupportedEncodingException ue) {
// Shouldn't happen.
ue.printStackTrace();
}
mSaveText = saveText;
mSavePage = savePage;
parent.freeParts(); // DCI: test!, put in finally?
}
public boolean containsKey(String paramName) {
if (paramName.equals("title") || paramName.equals("action") ||
paramName.equals("savetext") || paramName.equals("savepage")) {
return true;
}
return mParent.isParameterSet(paramName);
}
public String get(String paramName) {
if (paramName.equals("title")) {
return mTitle;
}
if (paramName.equals("action")) {
return mAction;
}
if (paramName.equals("savetext")) {
return mSaveText;
}
if (paramName.equals("savepage")) {
return mSavePage;
}
if (!containsKey(paramName)) {
return null;
}
return mParent.getParam(paramName);
}
}
private static class PluginRequest implements Request {
private final Query mQuery;
private final String mPath;
PluginRequest(HTTPRequest parent, String containerPrefix) { // DCI throws IOException {
for (String key : parent.getParameterNames()) {
String value = parent.getParam(key);
if (value.length() > 128) {
value = value.substring(0, 128) + "...";
}
System.err.println(String.format("[%s] => [%s]", key, value));
}
String path = parent.getPath();
if (!path.startsWith(containerPrefix)) {
// This should be impossible because of the way plugin requests are routed.
throw new RuntimeException("Request doesn't start with: " + containerPrefix);
}
System.err.println("Raw path: " + path);
path = path.substring(containerPrefix.length());
while(path.startsWith("/")) {
path = path.substring(1).trim();
}
mQuery = new PluginQuery(parent, path);
mPath = path;
}
public String getPath() { return mPath; }
public Query getQuery() { return mQuery; }
}
public String handle(HTTPRequest request) throws PluginHTTPException {
// DCI: cleanup container_prefix usage
try {
mWikiApp.setRequest(new PluginRequest(request, mWikiApp.getString("container_prefix", null)));
return mWikiApp.handle(mWikiApp);
} catch(AccessDeniedException accessDenied) {
throw new AccessDeniedPluginHTTPException(accessDenied.getMessage(),
mWikiApp.getString("container_prefix", null));
} catch(NotFoundException notFound) {
throw new NotFoundPluginHTTPException(notFound.getMessage(),
mWikiApp.getString("container_prefix", null));
} catch(RedirectException redirected) {
throw new RedirectPluginHTTPException(redirected.getMessage(),
redirected.getLocation());
} catch(ChildContainerException serverError) {
throw new ServerPluginHTTPException(serverError.getMessage(),
mWikiApp.getString("container_prefix", null));
}
}
public String handleHTTPGet(HTTPRequest request) throws PluginHTTPException {
return handle(request);
}
public String handleHTTPPost(HTTPRequest request) throws PluginHTTPException {
return handle(request);
}
}