/* 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 java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import freenet.client.HighLevelSimpleClient; import freenet.l10n.NodeL10n; import freenet.node.DarknetPeerNode; import freenet.node.Node; import freenet.node.NodeClientCore; import freenet.node.NodeStarter; import freenet.node.PeerManager; import freenet.support.HTMLNode; import freenet.support.Logger; import freenet.support.MultiValueTable; import freenet.support.SizeUtil; import freenet.support.api.HTTPRequest; import freenet.support.api.HTTPUploadedFile; public class N2NTMToadlet extends Toadlet { private Node node; private LocalFileN2NMToadlet browser; protected N2NTMToadlet(Node n, NodeClientCore core, HighLevelSimpleClient client) { super(client); browser = new LocalFileN2NMToadlet(core, client); this.node = n; } public Toadlet getBrowser() { return browser; } public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException, RedirectException { if(!ctx.checkFullAccess(this)) return; if (request.isParameterSet("peernode_hashcode")) { PageNode page = ctx.getPageMaker().getPageNode(l10n("sendMessage"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; String peernode_name = null; String input_hashcode_string = request.getParam("peernode_hashcode"); int input_hashcode = -1; try { input_hashcode = Integer.parseInt(input_hashcode_string); } catch (NumberFormatException e) { // ignore here, handle below } if (input_hashcode != -1) { DarknetPeerNode[] peerNodes = node.getDarknetConnections(); for (DarknetPeerNode pn: peerNodes) { int peer_hashcode = pn.hashCode(); if (peer_hashcode == input_hashcode) { peernode_name = pn.getName(); break; } } } if (peernode_name == null) { contentNode.addChild(createPeerInfobox("infobox-error", l10n("peerNotFoundTitle"), l10n("peerNotFoundWithHash", "hash", input_hashcode_string))); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } HashMap<String, String> peers = new HashMap<String, String>(); peers.put(input_hashcode_string, peernode_name); createN2NTMSendForm(pageNode, ctx.isAdvancedModeEnabled(), contentNode, ctx, peers); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } MultiValueTable<String, String> headers = new MultiValueTable<String, String>(); headers.put("Location", "/friends/"); ctx.sendReplyHeaders(302, "Found", headers, null, 0); } private String l10n(String key, String pattern[], String value[]) { return NodeL10n.getBase().getString("N2NTMToadlet." + key, pattern, value); } private String l10n(String key, String pattern, String value) { return NodeL10n.getBase().getString("N2NTMToadlet." + key, new String[] { pattern }, new String[] { value }); } private static String l10n(String key) { return NodeL10n.getBase().getString("N2NTMToadlet." + key); } /* * File size limit is 1 MiB (1024*1024 bytes) or 5% of maximum Java memory, whichever is greater. */ private static long maxSize(){ long memory = NodeStarter.getMemoryLimitBytes(); if(memory == Long.MAX_VALUE || memory <= 0) return 1024*1024; long maxMem = Math.round(0.05*memory); long limit = Math.max(maxMem, 1024*1024); return limit; } private static HTMLNode createPeerInfobox(String infoboxType, String header, String message) { HTMLNode infobox = new HTMLNode("div", "class", "infobox "+infoboxType); infobox.addChild("div", "class", "infobox-header", header); HTMLNode infoboxContent = infobox.addChild("div", "class", "infobox-content"); infoboxContent.addChild("#", message); HTMLNode list = infoboxContent.addChild("ul"); Toadlet.addHomepageLink(list); list.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/friends/", l10n("returnToFriends") }, l10n("friends")); return infobox; } public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException, RedirectException { if(!ctx.checkFullAccess(this)) return; //Browse button clicked. Redirect. if(request.isPartSet("n2nm-browse")) { try { throw new RedirectException(LocalFileN2NMToadlet.PATH); } catch (URISyntaxException e) { //Should be impossible because the browser is registered with .PATH. } return; } if (request.isPartSet("n2nm-upload") || request.isPartSet(LocalFileBrowserToadlet.selectFile) || request.isPartSet("send")) { File filename = null; String message = request.getPartAsStringFailsafe("message", 5 * 1024); message = message.trim(); if (message.length() > 1024) { this.writeTextReply(ctx, 400, "Bad request", l10n("tooLong")); return; } PageNode page = ctx.getPageMaker().getPageNode(l10n("processingSend"), ctx); HTMLNode pageNode = page.outer; HTMLNode contentNode = page.content; HTMLNode peerTableInfobox = contentNode.addChild("div", "class", "infobox infobox-normal"); DarknetPeerNode[] peerNodes = node.getDarknetConnections(); if(request.isPartSet(LocalFileBrowserToadlet.selectFile)) { String fnam = request.getPartAsStringFailsafe("filename", 1024); if(fnam != null && fnam.length() > 0) { filename = new File(fnam); if(!(filename.exists() && filename.canRead())) { peerTableInfobox.addChild("#", l10n("noSuchFileOrCannotRead")); Toadlet.addHomepageLink(peerTableInfobox); this.writeHTMLReply(ctx, 400, "OK", pageNode.generate()); return; } } } HTMLNode peerTable = peerTableInfobox.addChild("table", "class", "n2ntm-send-statuses"); HTMLNode peerTableHeaderRow = peerTable.addChild("tr"); peerTableHeaderRow.addChild("th", l10n("peerName")); peerTableHeaderRow.addChild("th", l10n("sendStatus")); for (DarknetPeerNode pn: peerNodes) { if (request.isPartSet("node_" + pn.hashCode())) { int status; if(filename != null) { try { status = pn.sendFileOffer(filename, message); } catch (IOException e) { peerTableInfobox.addChild("#", l10n("noSuchFileOrCannotRead")); Toadlet.addHomepageLink(peerTableInfobox); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } } else if(request.isPartSet("n2nm-upload")) { try{ HTTPUploadedFile file = request.getUploadedFile("n2nm-upload"); if(!file.getFilename().equals("")) { long size = request.getUploadedFile("n2nm-upload").getData().size(); if(size > 0) { long limit = maxSize(); if(size > limit){ peerTableInfobox.addChild("#", l10n("tooLarge", new String[] {"attempt", "limit"}, new String[] {SizeUtil.formatSize(size, true), SizeUtil.formatSize(limit, true)})); HTMLNode list = peerTableInfobox.addChild("ul"); Toadlet.addHomepageLink(list); list.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/friends/", l10n("returnToFriends") }, l10n("friends")); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } status = pn.sendFileOffer(request.getUploadedFile("n2nm-upload"), message); } } } catch (IOException e) { peerTableInfobox.addChild("#", l10n("uploadFailed")); Toadlet.addHomepageLink(peerTableInfobox); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } } status = pn.sendTextFeed(message); String sendStatusShort; String sendStatusLong; String sendStatusClass; if(status == PeerManager.PEER_NODE_STATUS_ROUTING_BACKED_OFF) { sendStatusShort = l10n("delayedTitle"); sendStatusLong = l10n("delayed"); sendStatusClass = "n2ntm-send-delayed"; Logger.normal(this, "Sent N2NTM to '" + pn.getName() + "': " + message); } else if(status == PeerManager.PEER_NODE_STATUS_CONNECTED) { sendStatusShort = l10n("sentTitle"); sendStatusLong = l10n("sent"); sendStatusClass = "n2ntm-send-sent"; Logger.normal(this, "Sent N2NTM to '" + pn.getName() + "': " + message); } else { sendStatusShort = l10n("queuedTitle"); sendStatusLong = l10n("queued"); sendStatusClass = "n2ntm-send-queued"; Logger.normal(this, "Queued N2NTM to '" + pn.getName() + "': " + message); } HTMLNode peerRow = peerTable.addChild("tr"); peerRow.addChild("td", "class", "peer-name").addChild("#", pn.getName()); peerRow.addChild("td", "class", sendStatusClass) .addChild("span", new String[] { "title", "style" }, new String[] { sendStatusLong, "border-bottom: 1px dotted; cursor: help;" }, sendStatusShort); } } HTMLNode infoboxContent = peerTableInfobox.addChild("div", "class", "n2ntm-message-text"); infoboxContent.addChild("#", message); HTMLNode list = peerTableInfobox.addChild("ul"); Toadlet.addHomepageLink(list); list.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/friends/", l10n("returnToFriends") }, l10n("friends")); this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); return; } MultiValueTable<String, String> headers = new MultiValueTable<String, String>(); headers.put("Location", "/friends/"); ctx.sendReplyHeaders(302, "Found", headers, null, 0); } public static void createN2NTMSendForm(HTMLNode pageNode, boolean advancedMode, HTMLNode contentNode, ToadletContext ctx, HashMap<String, String> peers) throws ToadletContextClosedException, IOException { HTMLNode infobox = contentNode.addChild("div", new String[] { "class", "id" }, new String[] { "infobox", "n2nbox" }); infobox.addChild("div", "class", "infobox-header", l10n("sendMessage")); HTMLNode messageTargets = infobox.addChild("div", "class", "infobox-content"); messageTargets.addChild("p", l10n("composingMessageLabel")); HTMLNode messageTargetList = messageTargets.addChild("ul"); // Iterate peers for (String peer_name: peers.values()) { messageTargetList.addChild("li", peer_name); } HTMLNode infoboxContent = infobox.addChild("div", "class", "infobox-content"); HTMLNode messageForm = ctx.addFormChild(infoboxContent, "/send_n2ntm/", "sendN2NTMForm"); // Iterate peers for (String peerNodeHash : peers.keySet()) { messageForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "node_" + peerNodeHash, "1" }); } messageForm.addChild("textarea", new String[] { "id", "name", "rows", "cols" }, new String[] { "n2ntmtext", "message", "8", "74" }); messageForm.addChild("br"); messageForm.addChild("#", NodeL10n.getBase().getString("N2NTMToadlet.mayAttachFile")); if(ctx.isAllowedFullAccess()) { messageForm.addChild("br"); messageForm.addChild("#", NodeL10n.getBase().getString("QueueToadlet.insertFileBrowseLabel")+": "); messageForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "n2nm-browse", NodeL10n.getBase().getString("QueueToadlet.insertFileBrowseButton") + "..." }); messageForm.addChild("br"); } if(advancedMode){ messageForm.addChild("#", NodeL10n.getBase().getString("N2NTMToadlet.sizeWarning", "limit", SizeUtil.formatSize(maxSize(), true))); messageForm.addChild("br"); messageForm.addChild("#", NodeL10n.getBase().getString("QueueToadlet.insertFileLabel") + ": "); messageForm.addChild("input", new String[] {"type", "name", "value" }, new String[] { "file", "n2nm-upload", "" }); messageForm.addChild("br"); } messageForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "send", l10n("sendMessageShort") }); } @Override public String path() { return "/send_n2ntm/"; } }