/* This code is part of Freenet. It is distributed under the GNU General * Public License, version 2 (or at your option any later version). See * http://www.gnu.org/ for further details of the GPL. */ package freenet.clients.http; import org.tanukisoftware.wrapper.WrapperManager; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.HashSet; import java.util.List; import freenet.client.ClientMetadata; import freenet.client.HighLevelSimpleClient; import freenet.client.InsertBlock; import freenet.client.InsertException; import freenet.client.InsertException.InsertExceptionMode; import freenet.clients.http.PageMaker.RenderParameters; import freenet.clients.http.bookmark.BookmarkCategory; import freenet.clients.http.bookmark.BookmarkItem; import freenet.clients.http.bookmark.BookmarkManager; import freenet.keys.FreenetURI; import freenet.l10n.NodeL10n; import freenet.node.DarknetPeerNode; import freenet.node.Node; import freenet.node.NodeStarter; import freenet.node.Version; import freenet.node.useralerts.UserAlert; import freenet.support.HTMLNode; import freenet.support.LogThresholdCallback; import freenet.support.Logger; import freenet.support.Logger.LogLevel; import freenet.support.MultiValueTable; import freenet.support.URLDecoder; import freenet.support.api.HTTPRequest; import freenet.support.api.RandomAccessBucket; import freenet.support.io.Closer; import freenet.support.io.FileUtil; import freenet.support.io.LineReadingInputStream; public class WelcomeToadlet extends Toadlet { /** Suffix {@link #path()} with "#" + BOOKMARKS_ANCHOR to deep link to the bookmark list */ public static final String BOOKMARKS_ANCHOR = "bookmarks"; final Node node; private static volatile boolean logMINOR; static { Logger.registerLogThresholdCallback(new LogThresholdCallback() { @Override public void shouldUpdate() { logMINOR = Logger.shouldLog(LogLevel.MINOR, this); } }); } WelcomeToadlet(HighLevelSimpleClient client, Node node) { super(client); this.node = node; } void redirectToRoot(ToadletContext ctx) throws ToadletContextClosedException, IOException { MultiValueTable<String, String> headers = new MultiValueTable<String, String>(); headers.put("Location", "/"); ctx.sendReplyHeaders(302, "Found", headers, null, 0); return; } private void addCategoryToList(BookmarkCategory cat, HTMLNode list, boolean noActiveLinks, ToadletContext ctx) { if(ctx.getPageMaker().getTheme().forceActivelinks) { noActiveLinks = false; } List<BookmarkItem> items = cat.getItems(); if (items.size() > 0) { // FIXME CSS noborder ... HTMLNode table = list.addChild("li").addChild("table", new String[]{"border", "style"}, new String[]{"0", "border: none"}); for (int i = 0; i < items.size(); i++) { BookmarkItem item = items.get(i); HTMLNode row = table.addChild("tr"); HTMLNode cell = row.addChild("td", "style", "border: none"); if (item.hasAnActivelink() && !noActiveLinks) { String initialKey = item.getKey(); String key = '/' + initialKey + (initialKey.endsWith("/") ? "" : "/") + "activelink.png"; cell.addChild("a", "href", '/' + item.getKey()).addChild("img", new String[]{"src", "height", "width", "alt", "title"}, new String[]{ key, "36", "108", "activelink", item.getDescription()}); } else { cell.addChild("#", " "); } cell = row.addChild("td", "style", "border: none"); boolean updated = item.hasUpdated(); // We use it twice so copy for thread safety String linkClass = updated ? "bookmark-title-updated" : "bookmark-title"; cell.addChild( "a", new String[]{"href", "title", "class"}, new String[]{'/' + item.getKey(), item.getDescription(), linkClass}, item.getVisibleName()); String explain = item.getShortDescription(); if(explain != null && explain.length() > 0) { cell.addChild("#", " ("); cell.addChild("#", explain); cell.addChild("#", ")"); } if (updated) { cell = row.addChild("td", "style", "border: none"); cell.addChild(node.clientCore.alerts.renderDismissButton( item.getUserAlert(), path() + "#" + BOOKMARKS_ANCHOR)); } } } List<BookmarkCategory> cats = cat.getSubCategories(); for (int i = 0; i < cats.size(); i++) { list.addChild("li", "class", "cat", cats.get(i).getVisibleName()); addCategoryToList(cats.get(i), list.addChild("li").addChild("ul"), noActiveLinks, ctx); } } public boolean allowPOSTWithoutPassword() { // We need to show some confirmation pages. return true; } public boolean showSearchBox() { // Only show it if Library is loaded. return (node.pluginManager != null && node.pluginManager.isPluginLoaded("plugins.Library.Main")); } public boolean showSearchBoxLoading() { // Only show it if Library is loaded. return (node.pluginManager == null || (!node.pluginManager.isPluginLoaded("plugins.Library.Main") && node.pluginManager.isPluginLoadedOrLoadingOrWantLoad("Library"))); } public void addSearchBox(HTMLNode contentNode) { // This function still contains legacy cruft because we might // need that again when Library becomes usable again. HTMLNode searchBox = contentNode.addChild("div", "class", "infobox infobox-normal"); searchBox.addAttribute("id", "search-freenet"); searchBox.addChild("div", "class", "infobox-header").addChild("span", "class", "search-title-label", NodeL10n.getBase().getString("WelcomeToadlet.searchBoxLabel")); HTMLNode searchBoxContent = searchBox.addChild("div", "class", "infobox-content"); // Search form if (showSearchBox()) { // FIXME: Remove this once we have a non-broken index. searchBoxContent.addChild("span", "class", "search-warning-text", l10n("searchBoxWarningSlow")); HTMLNode searchForm = container.addFormChild(searchBoxContent, "/library/", "searchform"); searchForm.addChild("input", new String[] { "type", "size", "name" }, new String[] { "text", "80", "search" }); searchForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "find", l10n("searchFreenet") }); // Search must be in a new window so that the user is able to browse the bookmarks. searchForm.addAttribute("target", "_blank"); } else if (showSearchBoxLoading()) { // Warn that search plugin is not loaded. HTMLNode textSpan = searchBoxContent.addChild("span", "class", "search-not-availible-warning"); NodeL10n.getBase().addL10nSubstitution(textSpan, "WelcomeToadlet.searchPluginLoading", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/plugins/") }); } else { // Warn that search plugin is not loaded. HTMLNode textSpan = searchBoxContent.addChild("span", "class", "search-not-availible-warning"); NodeL10n.getBase().addL10nSubstitution(textSpan, "WelcomeToadlet.searchPluginNotLoaded", new String[] { "link" }, new HTMLNode[] { HTMLNode.link("/plugins/") }); } } public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException { if(!ctx.checkFullAccess(this)) return; if (request.getPartAsStringFailsafe("updateconfirm", 32).length() > 0) { if(!ctx.checkFormPassword(request)) return; // false for no navigation bars, because that would be very silly PageNode page = ctx.getPageMaker().getPageNode(l10n("updatingTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode content = ctx.getPageMaker().getInfobox("infobox-information", l10n("updatingTitle"), contentNode, null, true); content.addChild("p").addChild("#", l10n("updating")); content.addChild("p").addChild("#", l10n("thanks")); writeHTMLReply(ctx, 200, "OK", pageNode.generate()); Logger.normal(this, "Node is updating/restarting"); node.getNodeUpdater().arm(); } else if (request.getPartAsStringFailsafe("update", 32).length() > 0) { PageNode page = ctx.getPageMaker().getPageNode(l10n("nodeUpdateConfirmTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode content = ctx.getPageMaker().getInfobox("infobox-query", l10n("nodeUpdateConfirmTitle"), contentNode, "update-node-confirm", true); content.addChild("p").addChild("#", l10n("nodeUpdateConfirm")); HTMLNode updateForm = ctx.addFormChild(content, "/", "updateConfirmForm"); updateForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel")}); updateForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "updateconfirm", l10n("update")}); writeHTMLReply(ctx, 200, "OK", pageNode.generate()); } else if (request.isPartSet("getThreadDump")) { if(!ctx.checkFormPassword(request)) return; PageNode page = ctx.getPageMaker().getPageNode(l10n("threadDumpTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; if (node.isUsingWrapper()) { ctx.getPageMaker().getInfobox("#", l10n("threadDumpSubTitle"), contentNode, "thread-dump-generation", true). addChild("#", l10n("threadDumpWithFilename", "filename", WrapperManager.getProperties().getProperty("wrapper.logfile"))); System.out.println("Thread Dump:"); WrapperManager.requestThreadDump(); } else { ctx.getPageMaker().getInfobox("infobox-error", l10n("threadDumpSubTitle"), contentNode, "thread-dump-generation", true). addChild("#", l10n("threadDumpNotUsingWrapper")); } this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); } else if (request.isPartSet("disable")) { if(!ctx.checkFormPassword(request)) return; int validAlertsRemaining = 0; UserAlert[] alerts = ctx.getAlertManager().getAlerts(); for (UserAlert alert: alerts) { if (request.getIntPart("disable", -1) == alert.hashCode()) { // Won't be dismissed if it's not allowed anyway if (alert.userCanDismiss() && alert.shouldUnregisterOnDismiss()) { alert.onDismiss(); Logger.normal(this, "Unregistering the userAlert " + alert.hashCode()); ctx.getAlertManager().unregister(alert); } else { Logger.normal(this, "Disabling the userAlert " + alert.hashCode()); alert.isValid(false); } } else if(alert.isValid()) { validAlertsRemaining++; } } writePermanentRedirect(ctx, l10n("disabledAlert"), (validAlertsRemaining > 0 ? "/alerts/" : "/")); return; } else if (request.isPartSet("key") && request.isPartSet("filename")) { if(!ctx.checkFormPassword(request)) return; // FIXME do we still use this? where? // FIXME If we support it from freesites we need a confirmation page with the formPassword. FreenetURI key = new FreenetURI(request.getPartAsStringFailsafe("key", Short.MAX_VALUE)); String type = request.getPartAsStringFailsafe("content-type", 128); if (type == null) { type = "text/plain"; } ClientMetadata contentType = new ClientMetadata(type); RandomAccessBucket bucket = request.getPart("filename"); PageNode page = ctx.getPageMaker().getPageNode(l10n("insertedTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode content; String filenameHint = null; if (key.getKeyType().equals("CHK")) { String[] metas = key.getAllMetaStrings(); if ((metas != null) && (metas.length > 1)) { filenameHint = metas[0]; } } InsertBlock block = new InsertBlock(bucket, contentType, key); try { key = this.insert(block, filenameHint, false); content = ctx.getPageMaker().getInfobox("infobox-success", l10n("insertSucceededTitle"), contentNode, "successful-insert", false); String u = key.toString(); NodeL10n.getBase().addL10nSubstitution(content, "WelcomeToadlet.keyInsertedSuccessfullyWithKeyAndName", new String[]{"link", "name"}, new HTMLNode[] { HTMLNode.link("/"+u), HTMLNode.text(u) }); } catch (InsertException e) { content = ctx.getPageMaker().getInfobox("infobox-error", l10n("insertFailedTitle"), contentNode, "failed-insert", false); content.addChild("#", l10n("insertFailedWithMessage", "message", e.getMessage())); content.addChild("br"); if (e.uri != null) { content.addChild("#", l10n("uriWouldHaveBeen", "uri", e.uri.toString())); } InsertExceptionMode mode = e.getMode(); if ((mode == InsertExceptionMode.FATAL_ERRORS_IN_BLOCKS) || (mode == InsertExceptionMode.TOO_MANY_RETRIES_IN_BLOCKS)) { content.addChild("br"); /* TODO */ content.addChild("#", l10n("splitfileErrorLabel")); content.addChild("pre", e.errorCodes.toVerboseString()); } } content.addChild("br"); addHomepageLink(content); writeHTMLReply(ctx, 200, "OK", pageNode.generate()); request.freeParts(); bucket.free(); return; } else if (request.isPartSet("key")) { if(!ctx.checkFormPassword(request)) return; String key; try { key = URLDecoder.decode(new FreenetURI(request.getPartAsStringFailsafe("key", Short.MAX_VALUE)).toURI("/").toString(), false); } catch (Exception e) { sendErrorPage(ctx, l10n("invalidURI"), l10n("invalidURILong"), e); return; } writeTemporaryRedirect(ctx, "OK", key); return; } else if (request.isPartSet("exit")) { PageNode page = ctx.getPageMaker().getPageNode(l10n("shutdownConfirmTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode content = ctx.getPageMaker().getInfobox("infobox-query", l10n("shutdownConfirmTitle"), contentNode, "shutdown-confirm", true); content.addChild("p").addChild("#", l10n("shutdownConfirm")); HTMLNode shutdownForm = ctx.addFormChild(content.addChild("p"), "/", "confirmShutdownForm"); shutdownForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel")}); shutdownForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "shutdownconfirm", l10n("shutdown")}); writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } else if (request.isPartSet("shutdownconfirm")) { if(!ctx.checkFormPassword(request)) return; MultiValueTable<String, String> headers = new MultiValueTable<String, String>(); headers.put("Location", "/?terminated&formPassword=" + ctx.getFormPassword()); ctx.sendReplyHeaders(302, "Found", headers, null, 0); node.ticker.queueTimedJob(new Runnable() { @Override public void run() { node.exit("Shutdown from fproxy"); } }, 1); return; } else if (request.isPartSet("restart")) { PageNode page = ctx.getPageMaker().getPageNode(l10n("restartConfirmTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode content = ctx.getPageMaker().getInfobox("infobox-query", l10n("restartConfirmTitle"), contentNode, "restart-confirm", true); content.addChild("p").addChild("#", l10n("restartConfirm")); HTMLNode restartForm = ctx.addFormChild(content.addChild("p"), "/", "confirmRestartForm"); restartForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "cancel", NodeL10n.getBase().getString("Toadlet.cancel")}); restartForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "restartconfirm", l10n("restart")}); writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } else if (request.isPartSet("restartconfirm")) { if(!ctx.checkFormPassword(request)) return; MultiValueTable<String, String> headers = new MultiValueTable<String, String>(); headers.put("Location", "/?restarted&formPassword=" + ctx.getFormPassword()); ctx.sendReplyHeaders(302, "Found", headers, null, 0); node.ticker.queueTimedJob(new Runnable() { @Override public void run() { node.getNodeStarter().restart(); } }, 1); return; } else if(request.isPartSet("dismiss-events")) { if(!ctx.checkFormPassword(request)) return; String alertsToDump = request.getPartAsStringFailsafe("events", Integer.MAX_VALUE); String[] alertAnchors = alertsToDump.split(","); HashSet<String> toDump = new HashSet<String>(); for(String alertAnchor : alertAnchors) toDump.add(alertAnchor); ctx.getAlertManager().dumpEvents(toDump); redirectToRoot(ctx); } else { redirectToRoot(ctx); } } public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException { if (ctx.isAllowedFullAccess()) { if (request.isParameterSet("latestlog")) { final File logs = new File(node.config.get("logger").getString("dirname") + File.separator + "freenet-latest.log"); String text = readLogTail(logs, 100000); this.writeTextReply(ctx, 200, "OK", text); return; } else if (request.isParameterSet("terminated")) { if ((!request.isParameterSet("formPassword")) || !request.getParam("formPassword").equals(ctx.getFormPassword())) { redirectToRoot(ctx); return; } // Tell the user that the node is shutting down PageNode page = ctx.getPageMaker().getPageNode("Node Shutdown", ctx, new RenderParameters().renderNavigationLinks(false)); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; ctx.getPageMaker().getInfobox("infobox-information", l10n("shutdownDone"), contentNode, "shutdown-progressing", true). addChild("#", l10n("thanks")); WelcomeToadlet.maybeDisplayWrapperLogfile(ctx, contentNode); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } else if (request.isParameterSet("restarted")) { if ((!request.isParameterSet("formPassword")) || !request.getParam("formPassword").equals(ctx.getFormPassword())) { redirectToRoot(ctx); return; } sendRestartingPage(ctx); return; } else if (request.getParam("newbookmark").length() > 0) { PageNode page = ctx.getPageMaker().getPageNode(l10n("confirmAddBookmarkTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode infoboxContent = ctx.getPageMaker().getInfobox("#", l10n("confirmAddBookmarkSubTitle"), contentNode, "add-bookmark-confirm", true); HTMLNode addForm = ctx.addFormChild(infoboxContent, "/bookmarkEditor/", "editBookmarkForm"); addForm.addChild("#", l10n("confirmAddBookmarkWithKey", "key", request.getParam("newbookmark"))); addForm.addChild("br"); String key = request.getParam("newbookmark"); if (key.startsWith("freenet:")) { key = key.substring(8); } addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"hidden", "key", key}); if(request.isParameterSet("hasAnActivelink")) { addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"hidden","hasAnActivelink",request.getParam("hasAnActivelink")}); } addForm.addChild("label", "for", "name", NodeL10n.getBase().getString("BookmarkEditorToadlet.nameLabel") + ' '); addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"text", "name", request.getParam("desc")}); addForm.addChild("br"); addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"hidden", "bookmark", "/"}); addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"hidden", "action", "addItem"}); addForm.addChild("label", "for", "descB", NodeL10n.getBase().getString("BookmarkEditorToadlet.descLabel") + ' '); addForm.addChild("br"); addForm.addChild("textarea", new String[]{"id", "name", "row", "cols"}, new String[]{"descB", "descB", "3", "70"}); if(node.getDarknetConnections().length > 0) { addForm.addChild("br"); addForm.addChild("br"); if (node.isFProxyJavascriptEnabled()) { addForm.addChild("script", new String[] {"type", "src"}, new String[] {"text/javascript", "/static/js/checkall.js"}); } HTMLNode peerTable = addForm.addChild("table", "class", "darknet_connections"); if (node.isFProxyJavascriptEnabled()) { HTMLNode headerRow = peerTable.addChild("tr"); headerRow.addChild("th").addChild("input", new String[] { "type", "onclick" }, new String[] { "checkbox", "checkAll(this, 'darknet_connections')" }); headerRow.addChild("th", NodeL10n.getBase().getString("QueueToadlet.recommendToFriends")); } else { peerTable.addChild("tr").addChild("th", "colspan", "2", NodeL10n.getBase().getString("QueueToadlet.recommendToFriends")); } for(DarknetPeerNode peer : node.getDarknetConnections()) { HTMLNode peerRow = peerTable.addChild("tr", "class", "darknet_connections_normal"); peerRow.addChild("td", "class", "peer-marker").addChild("input", new String[] { "type", "name" }, new String[] { "checkbox", "node_" + peer.hashCode() }); peerRow.addChild("td", "class", "peer-name").addChild("#", peer.getName()); } addForm.addChild("label", "for", "descB", (NodeL10n.getBase().getString("BookmarkEditorToadlet.publicDescLabel") + ' ')); addForm.addChild("br"); addForm.addChild("textarea", new String[]{"id", "name", "row", "cols"}, new String[]{"descB", "publicDescB", "3", "70"}, ""); } addForm.addChild("br"); addForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "addbookmark", NodeL10n.getBase().getString("BookmarkEditorToadlet.addBookmark")}); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } else if (uri.getQuery() != null && uri.getQuery().startsWith("_CHECKED_HTTP_=")) { //Redirect requests for escaped URLs using the old destination to ExternalLinkToadlet. super.writeTemporaryRedirect(ctx, "Depreciated", ExternalLinkToadlet.PATH+'?'+uri.getQuery()); return; } } PageNode page = ctx.getPageMaker().getPageNode(l10n("homepageFullTitle"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; String useragent = ctx.getHeaders().get("user-agent"); if (useragent != null) { useragent = useragent.toLowerCase(); if ((useragent.indexOf("msie") > -1) && (useragent.indexOf("opera") == -1)) { ctx.getPageMaker().getInfobox("infobox-alert", l10n("ieWarningTitle"), contentNode, "internet-explorer-used", true). addChild("#", l10n("ieWarning")); } } // Alerts if (ctx.isAllowedFullAccess()) { contentNode.addChild(ctx.getAlertManager().createSummary()); } if (ctx.getPageMaker().getTheme().fetchKeyBoxAboveBookmarks) { this.putFetchKeyBox(ctx, contentNode); } // Bookmarks HTMLNode bookmarkBox = contentNode.addChild("div", "class", "infobox infobox-normal bookmarks-box"); HTMLNode bookmarkBoxHeader = bookmarkBox.addChild("div", "class", "infobox-header"); bookmarkBoxHeader.addChild("a", new String[]{"class", "title"}, new String[]{"bookmarks-header-text", NodeL10n.getBase().getString("BookmarkEditorToadlet.myBookmarksExplanation")}, NodeL10n.getBase().getString("BookmarkEditorToadlet.myBookmarksTitle")); if (ctx.isAllowedFullAccess()) { bookmarkBoxHeader.addChild("span", "class", "edit-bracket", "["); bookmarkBoxHeader.addChild("span", "id", "bookmarkedit").addChild("a", new String[]{"href", "class"}, new String[]{"/bookmarkEditor/", "interfacelink"}, NodeL10n.getBase().getString("BookmarkEditorToadlet.edit")); bookmarkBoxHeader.addChild("span", "class", "edit-bracket", "]"); } HTMLNode bookmarkBoxContent = bookmarkBox.addChild("div", "class", "infobox-content"); HTMLNode bookmarksList = bookmarkBoxContent.addChild("ul", "id", BOOKMARKS_ANCHOR); if (ctx.isAllowedFullAccess() || !ctx.getContainer().publicGatewayMode()) { addCategoryToList(BookmarkManager.MAIN_CATEGORY, bookmarksList, (!container.enableActivelinks()) || (useragent != null && useragent.contains("khtml") && !useragent.contains("chrome")), ctx); } else { addCategoryToList(BookmarkManager.DEFAULT_CATEGORY, bookmarksList, (!container.enableActivelinks()) || (useragent != null && useragent.contains("khtml") && !useragent.contains("chrome")), ctx); } // Search Box if (showSearchBox()) { addSearchBox(contentNode); } // Fetch key box if the theme wants it below the bookmarks. if (!ctx.getPageMaker().getTheme().fetchKeyBoxAboveBookmarks) { this.putFetchKeyBox(ctx, contentNode); } // Version info and Quit Form HTMLNode versionContent = ctx.getPageMaker().getInfobox("infobox-information", l10n("versionHeader"), contentNode, "freenet-version", true); versionContent.addChild("span", "class", "freenet-full-version", NodeL10n.getBase().getString("WelcomeToadlet.version", new String[]{"fullVersion", "build", "rev"}, new String[]{Version.publicVersion(), Integer.toString(Version.buildNumber()), Version.cvsRevision()})); versionContent.addChild("br"); versionContent.addChild("span", "class", "freenet-ext-version", NodeL10n.getBase().getString("WelcomeToadlet.extVersion", new String[]{"build", "rev"}, new String[]{Integer.toString(NodeStarter.extBuildNumber), NodeStarter.extRevisionNumber})); versionContent.addChild("br"); if (ctx.isAllowedFullAccess()) { HTMLNode shutdownForm = ctx.addFormChild(versionContent, ".", "shutdownForm"); shutdownForm.addChild("input", new String[]{"type", "name"}, new String[]{"hidden", "exit"}); shutdownForm.addChild("input", new String[]{"type", "value"}, new String[]{"submit", l10n("shutdownNode")}); if (node.isUsingWrapper()) { HTMLNode restartForm = ctx.addFormChild(versionContent, ".", "restartForm"); restartForm.addChild("input", new String[]{"type", "name"}, new String[]{"hidden", "restart"}); restartForm.addChild("input", new String[]{"type", "name", "value"}, new String[]{"submit", "restart2", l10n("restartNode")}); } } this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); } private void putFetchKeyBox(ToadletContext ctx, HTMLNode contentNode) { // Fetch-a-key box HTMLNode fetchKeyContent = ctx.getPageMaker().getInfobox("infobox-normal", l10n("fetchKeyLabel"), contentNode, "fetch-key", true); fetchKeyContent.addAttribute("id", "keyfetchbox"); HTMLNode fetchKeyForm = fetchKeyContent.addChild("form", new String[]{ "method" }, new String[]{ "POST" }).addChild("div"); fetchKeyForm.addChild("span", "class", "fetch-key-label", l10n("keyRequestLabel") + ' '); fetchKeyForm.addChild("input", new String[]{ "type", "size", "name" }, new String[]{ "text", "80", "key" }); fetchKeyForm.addChild("input", new String[]{ "type", "name", "value" }, new String[]{ "hidden", "formPassword", ctx.getFormPassword() }); fetchKeyForm.addChild("input", new String[]{ "type", "value" }, new String[]{ "submit", l10n("fetch") }); } private void sendRestartingPage(ToadletContext ctx) throws ToadletContextClosedException, IOException { writeHTMLReply(ctx, 200, "OK", sendRestartingPageInner(ctx).generate()); } static HTMLNode sendRestartingPageInner(ToadletContext ctx) { // Tell the user that the node is restarting PageNode page = ctx.getPageMaker().getPageNode("Node Restart", ctx, new RenderParameters().renderNavigationLinks(false)); HTMLNode pageNode = page.outer; HTMLNode headNode = page.headNode; headNode.addChild("meta", new String[]{"http-equiv", "content"}, new String[]{"refresh", "20; url="}); HTMLNode contentNode = page.content; ctx.getPageMaker().getInfobox("infobox-information", l10n("restartingTitle"), contentNode, "shutdown-progressing", true). addChild("#", l10n("restarting")); Logger.normal(WelcomeToadlet.class, "Node is restarting"); return pageNode; } private static String l10n(String key) { return NodeL10n.getBase().getString("WelcomeToadlet." + key); } private static String l10n(String key, String pattern, String value) { return NodeL10n.getBase().getString("WelcomeToadlet." + key, new String[]{pattern}, new String[]{value}); } public static void maybeDisplayWrapperLogfile(ToadletContext ctx, HTMLNode contentNode) { final File logs = new File("wrapper.log"); long logSize = logs.length(); if(logs.exists() && logs.isFile() && logs.canRead() && (logSize > 0)) { HTMLNode logInfoboxContent = ctx.getPageMaker().getInfobox("infobox-info", "Current status", contentNode, "start-progress", true); LineReadingInputStream logreader = null; try { logreader = FileUtil.getLogTailReader(logs, 2000); String line; while ((line = logreader.readLine(100000, 200, true)) != null) { logInfoboxContent.addChild("#", line); logInfoboxContent.addChild("br"); } } catch(IOException e) {} finally { Closer.close(logreader); } } } /** * Reads and returns the content of <code>logfile</code>. At most <code>byteLimit</code> * bytes will be read. If <code>byteLimit</code> is less than the size of <code>logfile</code>, * the first part of the file will be skipped. If this leaves a partial line at the beginning * of the content to return, that partial line will also be skipped. * @param logfile The file to read * @param byteLimit The maximum number of bytes to read * @return The trailing portion of the file * @throws IOException if an I/O error occurs */ private static String readLogTail(File logfile, long byteLimit) throws IOException { LineReadingInputStream stream = null; try { stream = FileUtil.getLogTailReader(logfile, byteLimit); return FileUtil.readUTF(stream).toString(); } finally { Closer.close(stream); } } public static final String PATH = "/"; @Override public String path() { // So it matches "Browse Freenet" on the menu return PATH; } }