First pass at configuration UI.
diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -2,7 +2,6 @@ <property name="src" value="./src" /> <property name="alien.src" value="./alien/src" /> <property name="alien.libs" value="./alien/libs" /> - <property name="plugin.src" value="./plugin/src" /> <property name="classes" value="./build/classes" /> <property name="jars" value="./build/jar" /> diff --git a/readme.txt b/readme.txt --- a/readme.txt +++ b/readme.txt @@ -1,10 +1,19 @@ -20110126 +------------------------------------------------------------ +This is a my personal work repo. Unless you pull a version +tagged as a release (none yet), you can assume that code +may be buggy / broken. + +-- djk + +------------------------------------------------------------ + +20110130 djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks WARNING: THIS IS RAW ALPHA CODE. -I'm releasing this so that other developers in the Freenet community +I'm publishing this so that other developers in the Freenet community can audit the source code. DON'T USE IT if violation of your anonymity would put you at risk. @@ -30,14 +39,28 @@ Edit the script/jfniki.sh to set PRIVATE Look at http://127.0.0.1:8083 with your web browser. BUILD FREENET PLUGIN: -The plugin code is included in the jfniki.jar but there is no UI for configuration yet, -so you have to edit the source code and recompile. - -Manually edit plugin/src/fniki/plugin/Fniki.java to include your FMS_ID and PRIVATE_FMS_SSK. - ant jar load the jar file from ./build/jar/jfniki.jar +Click on the "View Configuration" link and set the "FMS Private SSK" and "FMS ID fields". + + KNOWN ISSUES: o Pages don't auto-refresh. You need to manually reload to see status changes. [Freenet ContentFilter is eating meta-refresh???] + + +------------------------------------------------------------ +Dev notes: +------------------------------------------------------------ +Stopped in the middle of implementing config ui state +- figure out how to make private ssk wrap +- implement update msgs (mMsg) +- implement import / export +- test in plugin (probably broken at the moment) + +------------------------------------------------------------ + + + + diff --git a/src/fniki/freenet/filter/WikiContentFilter.java b/src/fniki/freenet/filter/WikiContentFilter.java --- a/src/fniki/freenet/filter/WikiContentFilter.java +++ b/src/fniki/freenet/filter/WikiContentFilter.java @@ -76,8 +76,14 @@ class WikiContentFilter implements Conte * @throws CommentException If the URI is nvalid or unacceptable in some way. */ public String processURI(String uri, String overrideType, boolean noRelative, boolean inline) throws CommentException { - // DCI: understand these parameters! + // inline is true for images (which we allow mod URI filtering). + // noRelative is true if you must return an absolute URI, which we don't allow. System.err.println("processURI(1): " + uri + " : " + overrideType + " : " + noRelative + " : " + inline); + if (noRelative) { + System.err.println("processURI(1): REJECTED URI because of noRelative."); + filterTripped(); + return null; + } return processURI(uri, overrideType); } diff --git a/src/fniki/freenet/plugin/Fniki.java b/src/fniki/freenet/plugin/Fniki.java --- a/src/fniki/freenet/plugin/Fniki.java +++ b/src/fniki/freenet/plugin/Fniki.java @@ -26,6 +26,7 @@ package fniki.freenet.plugin; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.Set; import freenet.pluginmanager.AccessDeniedPluginHTTPException; import freenet.pluginmanager.FredPlugin; @@ -39,6 +40,7 @@ import freenet.support.api.HTTPRequest; import fniki.wiki.ArchiveManager; import fniki.wiki.Query; +import fniki.wiki.QueryBase; import fniki.wiki.Request; import fniki.wiki.WikiApp; @@ -58,23 +60,9 @@ public class Fniki implements FredPlugin 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.setPrivateSSK("FMS_PRIVATE_SSK"); + archiveManager.setFmsId("SET_THE_FMS_ID"); archiveManager.createEmptyArchive(); WikiApp wikiApp = new WikiApp(archiveManager); @@ -82,8 +70,7 @@ public class Fniki implements FredPlugin if (containerPrefix == null) { throw new RuntimeException("Assertion Failure: container_prefix not set!"); } - wikiApp.setFproxyPrefix(fproxyPrefix); - wikiApp.setAllowImages(enableImages); + wikiApp.setAllowImages(false); // User can enable // IMPORTANT: // HTTP POSTS will be rejected without any useful error message if your form @@ -107,96 +94,63 @@ public class Fniki implements FredPlugin } } - private static class PluginQuery implements Query { + private static class PluginQuery extends QueryBase { private final HTTPRequest mParent; - private final String mTitle; - private final String mAction; - private final String mSaveText; - private final String mSavePage; + private final String mPath; - PluginQuery(HTTPRequest parent, String path) { - mParent = parent; + public void readParams() throws IOException { + Set<String> allParams = paramsSet(); - String title = path; - if (parent.isParameterSet("title")) { - title = parent.getParam("title"); + // Read normal non-multipart params. + for (String name : allParams) { + if (!mParent.isParameterSet(name)) { + continue; + } + mParamTable.put(name, mParent.getParam(name)); + System.err.println("Set Param: " + name + " : " + mParamTable.get(name)); } - 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 = ""; + // Then read multipart params if there are any. try { - for (String part : parent.getParts()) { - if (part.equals("savetext")) { - // DCI: magic numbers - saveText = new String(parent.getPartAsBytesFailsafe(part, 64 * 1024), "utf-8"); + for (String part : mParent.getParts()) { + if (!allParams.contains(part)) { continue; } - if (part.equals("savepage")) { - savePage = new String(parent.getPartAsBytesFailsafe(part, 64 * 1024), "utf-8"); - } + + String value = new String(mParent.getPartAsBytesFailsafe(part, 64 * 1024), "utf-8"); + mParamTable.put(part, value); + System.err.println("Set multipart Param: " + part + " : " + + mParamTable.get(part)); } } catch (UnsupportedEncodingException ue) { // Shouldn't happen. ue.printStackTrace(); } - mSaveText = saveText; - mSavePage = savePage; - parent.freeParts(); // DCI: test!, put in finally? + if (!mParamTable.containsKey("action")) { + System.err.println("Forced default action to view"); + mParamTable.put("action", "view"); + } + // DCI: title validation? + if (!mParamTable.containsKey("title")) { + mParamTable.put("title", mPath); + } + mParent.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); + PluginQuery(HTTPRequest parent, String path) throws IOException { + super(); + mParent = parent; + mPath = path; + readParams(); } } 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)); - } - + PluginRequest(HTTPRequest parent, String containerPrefix) throws IOException { String path = parent.getPath(); if (!path.startsWith(containerPrefix)) { // This should be impossible because of the way plugin requests are routed. @@ -235,7 +189,11 @@ public class Fniki implements FredPlugin } catch(ChildContainerException serverError) { throw new ServerPluginHTTPException(serverError.getMessage(), mWikiApp.getString("container_prefix", null)); + } catch(IOException ioError) { + throw new ServerPluginHTTPException(ioError.getMessage(), + mWikiApp.getString("container_prefix", null)); } + } public String handleHTTPGet(HTTPRequest request) throws PluginHTTPException { diff --git a/src/fniki/standalone/FnikiContextHandler.java b/src/fniki/standalone/FnikiContextHandler.java --- a/src/fniki/standalone/FnikiContextHandler.java +++ b/src/fniki/standalone/FnikiContextHandler.java @@ -26,9 +26,12 @@ package fniki.standalone; import java.io.IOException; import java.io.ByteArrayOutputStream; +import java.util.Map; +import java.util.Set; import net.freeutils.httpserver.HTTPServer; import fniki.wiki.Query; +import fniki.wiki.QueryBase; import fniki.wiki.Request; import fniki.wiki.WikiApp; @@ -42,10 +45,9 @@ public class FnikiContextHandler impleme private final WikiApp mApp; private final String mContainerPrefix; - private static class WikiQuery implements Query { + private static class WikiQuery extends QueryBase { private final HTTPServer.Request mParent; - private final String mSaveText; - private final String mSavePage; + private final String mPath; // Hmmmm... can't figure out any other way to know when part is done. private final String readAsUtf8(HTTPServer.MultipartIterator.Part part) throws IOException { @@ -62,52 +64,51 @@ public class FnikiContextHandler impleme return new String(baos.toByteArray(), "utf8"); } + public void readParams() throws IOException { + Set<String> allParams = paramsSet(); - WikiQuery(HTTPServer.Request parent) throws IOException { - mParent = parent; + // Read normal non-multipart params. + Map<String, String> parentParams = mParent.getParams(); + for (String name : allParams) { + if (!parentParams.containsKey(name)) { + continue; + } + System.err.println("Set Param: " + name + " : " + parentParams.get(name)); + mParamTable.put(name, parentParams.get(name)); + } - String saveText = null; - String savePage = null; - if (parent.getHeaders().getParams("Content-Type"). + // Then read multipart params if there are any. + if (mParent.getHeaders().getParams("Content-Type"). containsKey("multipart/form-data")) { - HTTPServer.MultipartIterator iter = new HTTPServer.MultipartIterator(parent); + HTTPServer.MultipartIterator iter = new HTTPServer.MultipartIterator(mParent); while (iter.hasNext()) { HTTPServer.MultipartIterator.Part part = iter.next(); - if (part.name.equals("savetext")) { - saveText = readAsUtf8(part); - } else if (part.name.equals("savepage")) { - savePage = readAsUtf8(part); + if (!allParams.contains(part.name)) { + continue; } + mParamTable.put(part.name, readAsUtf8(part)); + System.err.println("Set multipart Param: " + part.name + " : " + + mParamTable.get(part.name)); } - parent.consumeBody(); + mParent.consumeBody(); } - mSaveText = saveText; - mSavePage = savePage; - } - public boolean containsKey(String paramName) { - try { - if (paramName.equals("savetext")) { - return mSaveText != null; - } else if (paramName.equals("savepage")) { - return mSavePage != null; - } - return mParent.getParams().containsKey(paramName); - } catch (IOException ioe) { - return false; + + if (!mParamTable.containsKey("action")) { + System.err.println("Forced default action to view"); + mParamTable.put("action", "view"); + } + + // DCI: title validation? + if (!mParamTable.containsKey("title")) { + mParamTable.put("title", mPath); } } - public String get(String paramName) { - try { - if (paramName.equals("savetext")) { - return mSaveText; - } else if (paramName.equals("savepage")) { - return mSavePage; - } - return mParent.getParams().get(paramName); - } catch (IOException ioe) { - return null; - } + WikiQuery(HTTPServer.Request parent, String path) throws IOException { + super(); + mParent = parent; + mPath = path; + readParams(); } } @@ -116,15 +117,6 @@ public class FnikiContextHandler impleme private final String mPath; WikiRequest(HTTPServer.Request parent, String containerPrefix) throws IOException { - mQuery = new WikiQuery(parent); - for (String key : parent.getParams().keySet()) { - String value = parent.getParams().get(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 HTTPServer routes requests. @@ -138,26 +130,8 @@ public class FnikiContextHandler impleme path = path.substring(1).trim(); } - // DCI: not sure that this stuff belongs here. - String title = path; - if (mQuery.containsKey("title")) { - title = mQuery.get("title"); - } else { - parent.getParams().put("title", title); - } - - // DCI: validate title here - - String action = "view"; - if (mQuery.containsKey("action")) { - action = mQuery.get("action"); - } else { - parent.getParams().put("action", action); - } mPath = path; - - - + mQuery = new WikiQuery(parent, path); } public String getPath() { return mPath; } diff --git a/src/fniki/wiki/ArchiveManager.java b/src/fniki/wiki/ArchiveManager.java --- a/src/fniki/wiki/ArchiveManager.java +++ b/src/fniki/wiki/ArchiveManager.java @@ -49,7 +49,7 @@ public class ArchiveManager { private final static String FMS_HOST = "127.0.0.1"; private final static int FMS_PORT = 1119; private final static String FMS_GROUP = "biss.test000"; - private final static String BISS_NAME = "jfniki"; + private final static String BISS_NAME = "testwiki"; // Maximum number of versions to read from FMS. private final static int MAX_VERSIONS = 50; @@ -94,12 +94,25 @@ public class ArchiveManager { mFmsId = value; } + public String getFmsId() { return mFmsId; } + public void setFcpHost(String value) {mFcpHost = value; } + public String getFcpHost() { return mFcpHost; } + public void setFcpPort(int value) {mFcpPort = value; } + public int getFcpPort() { return mFcpPort; } + public void setFmsHost(String value) { mFmsHost = value; } + public String getFmsHost() { return mFmsHost; } + public void setFmsPort(int value) { mFmsPort = value; } + public int getFmsPort() { return mFmsPort; } + public void setFmsGroup(String value) { mFmsGroup = value; } + public String getFmsGroup() { return mFmsGroup; } + public void setBissName(String value) { mBissName= value; } + public String getBissName() { return mBissName; } // DCI: Fix this to roll back state on exceptions. public void load(String uri) throws IOException { diff --git a/src/fniki/wiki/QueryBase.java b/src/fniki/wiki/QueryBase.java new file mode 100644 --- /dev/null +++ b/src/fniki/wiki/QueryBase.java @@ -0,0 +1,66 @@ +/* Base class for writing Query implmentations for a specific HTTP framework. + * + * 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.wiki; + +import java.io.IOException; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + + +public abstract class QueryBase implements Query { + protected Map<String, String> mParamTable = new HashMap<String, String>(); + + // MUST contain every parameter used by any ChildContainer. + protected final static String PARAMS[] = new String[] { + "action", + "uri", "goto", + "savepage", "savetext", + "formPassword", + "saved", "discarded", "done", + // C&P from SettingConfig.java + "fcphost", "fcpport", "fpprefix", "fmshost", "fmsport", + "fmsssk", "fmsid", "wikiname", "images", + }; + + protected static Set<String> paramsSet() { + return new HashSet(Arrays.asList(PARAMS)); + } + + public boolean containsKey(String paramName) { + return mParamTable.containsKey(paramName); + } + + public String get(String paramName) { + return mParamTable.get(paramName); + } + + // Subclass should define this and call it once after construction. + public abstract void readParams() throws IOException; +} diff --git a/src/fniki/wiki/WikiApp.java b/src/fniki/wiki/WikiApp.java --- a/src/fniki/wiki/WikiApp.java +++ b/src/fniki/wiki/WikiApp.java @@ -44,6 +44,7 @@ import fniki.wiki.child.LoadingArchive; import fniki.wiki.child.LoadingChangeLog; import fniki.wiki.child.LoadingVersionList; import fniki.wiki.child.QueryError; +import fniki.wiki.child.SettingConfig; import fniki.wiki.child.Submitting; import fniki.wiki.child.WikiContainer; @@ -59,7 +60,8 @@ public class WikiApp implements ChildCon private final ChildContainer mQueryError; private final ChildContainer mWikiContainer; - // Containers for asynchronous tasks. + // ChildContainers for modal UI states. + private final ChildContainer mSettingConfig; private final ChildContainer mLoadingVersionList; private final ChildContainer mLoadingArchive; private final ChildContainer mSubmitting; @@ -94,6 +96,7 @@ public class WikiApp implements ChildCon mQueryError = new QueryError(); mWikiContainer = new WikiContainer(); + mSettingConfig = new SettingConfig(this, archiveManager); mLoadingVersionList = new LoadingVersionList(archiveManager); mLoadingArchive = new LoadingArchive(archiveManager); mSubmitting = new Submitting(archiveManager); @@ -195,8 +198,9 @@ public class WikiApp implements ChildCon } System.err.println("WikiApp.routeRequest: " + path); - if (path.equals("fniki/submit")) { - System.err.println("BC0"); + if (path.equals("fniki/config")) { + return setState(request, mSettingConfig); + } else if (path.equals("fniki/submit")) { return setState(request, mSubmitting); } else if (path.equals("fniki/changelog")) { return setState(request, mLoadingChangeLog); diff --git a/src/fniki/wiki/child/SettingConfig.java b/src/fniki/wiki/child/SettingConfig.java new file mode 100644 --- /dev/null +++ b/src/fniki/wiki/child/SettingConfig.java @@ -0,0 +1,205 @@ +/* A UI subcomponent to display and set the configuration. + * + * 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.wiki.child; + +import fniki.wiki.ArchiveManager; +import fniki.wiki.ChildContainerException; +import static fniki.wiki.HtmlUtils.*; +import fniki.wiki.ModalContainer; +import fniki.wiki.Query; +import fniki.wiki.WikiApp; +import fniki.wiki.WikiContext; + +public class SettingConfig implements ModalContainer { + private final WikiApp mWikiApp; + private final ArchiveManager mArchiveManager; + + private boolean mFinished = false; + private String mMsg = ""; + + public SettingConfig(WikiApp wikiApp, ArchiveManager archiveManager) { + mWikiApp = wikiApp; + mArchiveManager = archiveManager; + } + + private void handlePost(WikiContext context) throws ChildContainerException { + Query query = context.getQuery(); + if (query.containsKey("discarded")) { + mMsg = "Discarded changes."; + return; + } + + if (query.containsKey("done")) { + // Causes the routing logic in WikiApp.routeRequest to transition + // out of this modal ui state. + String redirectHref = makeHref(context.makeLink("/fniki/config"), + "finished", null, null, null); + context.raiseRedirect(redirectHref, "Redirecting..."); + } + + if (!query.containsKey("saved")) { + return; // Not sure how this would happen + } + + for (String key : FORM_FIELDS) { + if (!query.containsKey(key)) { + continue; + } + if (key.equals("fcphost")) { mArchiveManager.setFcpHost(query.get(key)); } + if (key.equals("fcpport")) { mArchiveManager.setFcpPort(Integer.parseInt(query.get(key))); } + + if (key.equals("fpprefix")) { mWikiApp.setFproxyPrefix(query.get(key)); } + + if (key.equals("fmshost")) { mArchiveManager.setFmsHost(query.get(key)); } + if (key.equals("fmsport")) { mArchiveManager.setFmsPort(Integer.parseInt(query.get(key))); } + + if (key.equals("fmsssk")) { mArchiveManager.setPrivateSSK(query.get(key)); } + if (key.equals("fmsid")) { mArchiveManager.setFmsId(query.get(key)); } + + if (key.equals("wikiname")) { mArchiveManager.setBissName(query.get(key)); } + } + + // Don't "images" not set in query params when box unchecked. + if (query.containsKey("images")) { + System.err.println("images: SET"); + mWikiApp.setAllowImages(true); + } else { + System.err.println("images: CLEARED"); + mWikiApp.setAllowImages(false); + } + } + + private static String noNulls(String text) { + if (text == null) { + return ""; + } + return text; + } + + // DCI: back over this. escape quotes. + public String handle(WikiContext context) throws ChildContainerException { + handlePost(context); + // DCI: Hmmm... it would be more pedantic to use the context interface for all of these. + + String href = makeHref(context.makeLink("/fniki/config"), + null, null, null, null); + + System.err.println("images allowd: " + context.getInt("allow_images", 0)); + return String.format(formTemplate(), + href, + noNulls(mArchiveManager.getFcpHost()), + Integer.toString(mArchiveManager.getFcpPort()), + context.getString("fproxy_prefix", "http://127.0.0.1:8888/"), + noNulls(mArchiveManager.getFmsHost()), + Integer.toString(mArchiveManager.getFmsPort()), + noNulls(mArchiveManager.getPrivateSSK()), + noNulls(mArchiveManager.getFmsId()), + noNulls(mArchiveManager.getFmsGroup()), + noNulls(mArchiveManager.getBissName()), + (context.getInt("allow_images", 0) == 1) ? "checked" : "", + // IMPORTANT: Won't work as a plugin without this. + context.getString("form_password", "FORM_PASSWORD_NOT_SET")); + } + + public boolean isFinished() {return mFinished; } + public void cancel() { mFinished = true; } + public void entered(WikiContext context) { + mFinished = false; + mMsg = ""; + } + public void exited() {} + + ////////////////////////////////////////////////// + private static final String FORM_FIELDS[] = new String[] { + "fcphost", "fcpport", "fpprefix", "fmshost", "fmsport", + "fmsssk", "fmsid", "wikiname", "images", + }; + + private static String formTemplate() { + StringBuilder sb = new StringBuilder(); + +sb.append("<html>\n"); +sb.append("<head>\n"); +sb.append("<title>\n"); +sb.append(" Configuration\n"); +sb.append("</title>\n"); +sb.append("</head>\n"); +sb.append("<body>\n"); +sb.append("<h1>Configuration</h1>\n"); +sb.append("<form method=\"post\" action=\"%s\" enctype=\"multipart/form-data\" accept-charset=\"UTF-8\">\n"); +sb.append("<table>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>Fcp Host</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fcphost\" value=\"%s\" /></td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>Fcp Port</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fcpport\" value=\"%s\" /></td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>Fproxy Prefix</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fpprefix\" size=\"64\" value=\"%s\" /></td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>FMS Host</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fmshost\" value=\"%s\" /></td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>FMS Port</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fmsport\" value=\"%s\" /> </td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>FMS Private SSK</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fmsssk\" size=\"128\" value=\"%s\" /> </td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>FMS ID</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fmsid\" value=\"%s\" /> </td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>FMS Group</td>\n"); +sb.append(" <td><input type=\"text\" name=\"fmsgroup\" value=\"%s\" /> </td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>Wiki Name</td>\n"); +sb.append(" <td><input type=\"text\" name=\"wikiname\" value=\"%s\"/> </td>\n"); +sb.append(" </tr>\n"); +sb.append(" <tr>\n"); +sb.append(" <td>Enable Images: <input type=\"checkbox\" name=\"images\" %s/></td>\n"); +sb.append(" </tr>\n"); +sb.append(" <input type=\"hidden\" name=\"formPassword\" value=\"%s\"/>\n"); +sb.append("</table>\n"); +sb.append("<input name=\"saved\" type=\"submit\" value=\"Save Changes\"/>\n"); +sb.append("<input name=\"discarded\" type=\"submit\" value=\"Discard Changes\"/>\n"); +sb.append("<input name=\"done\" type=\"submit\" value=\"Done\"/>\n"); +sb.append("</form>\n"); +sb.append("\n"); +sb.append("</body>\n"); +sb.append("</html>\n"); + + return sb.toString(); + } +} + diff --git a/src/fniki/wiki/child/WikiContainer.java b/src/fniki/wiki/child/WikiContainer.java --- a/src/fniki/wiki/child/WikiContainer.java +++ b/src/fniki/wiki/child/WikiContainer.java @@ -198,6 +198,9 @@ public class WikiContainer implements Ch buffer.append(makeLocalLink(context, "fniki/getversions", "confirm", "Discover")); buffer.append(" other recent version.<br>"); + buffer.append(makeLocalLink(context, "fniki/config", "view", "View")); + buffer.append(" configuration.<br>"); + buffer.append("</body></html>"); } @@ -218,10 +221,6 @@ public class WikiContainer implements Ch // the Freenet ContentFilter rewrites the encoding in all forms // to this value. buffer.append("multipart/form-data"); - - System.err.println("Sending form encoding: " + context.getString("form_encoding", "application/x-www-form-urlencoded")); - - buffer.append("\" accept-charset=\"UTF-8\">\n"); buffer.append("<input type=hidden name=\"savepage\" value=\"");