Author: zothar
Date: 2006-05-27 00:53:10 +0000 (Sat, 27 May 2006)
New Revision: 8879
Added:
trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java
trunk/freenet/src/freenet/node/useralerts/N2NTMUserAlert.java
Modified:
trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
trunk/freenet/src/freenet/clients/http/FProxyToadlet.java
trunk/freenet/src/freenet/io/comm/DMT.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/NodeDispatcher.java
Log:
Added very basic, unthemed local node to node text message support. Feel free
to make it look better. :)
Modified: trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-05-26 19:30:28 UTC (rev 8878)
+++ trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-05-27 00:53:10 UTC (rev 8879)
@@ -33,8 +33,8 @@
Integer stat1 = (Integer) row1[2];
int x = stat0.compareTo(stat1);
if(x != 0) return x;
- String name0 = (String) row0[3]; // 3 = node name
- String name1 = (String) row1[3];
+ String name0 = (String) row0[9]; // 9 = node name
+ String name1 = (String) row1[9];
return
name0.toLowerCase().compareTo(name1.toLowerCase());
}
@@ -114,7 +114,7 @@
long idle = pn.lastReceivedPacketTime();
// Elements must be HTML encoded.
- Object[] row = new Object[9]; // where [0] is
the pn object!
+ Object[] row = new Object[10]; // where [0] is
the pn object and 9 is the node name only for sorting!
rows[i] = row;
Object status = new
Integer(pn.getPeerNodeStatus());
@@ -132,18 +132,24 @@
VersionPrefixString = "<span
class=\"peer_version_problem\">";
VersionSuffixString = "</span>";
}
+ String NamePrefixString = "";
+ String NameSuffixString = "";
+ if(pn.isConnected()) {
+ NamePrefixString = "<a
href=\"/send_n2ntm/?peernode_hashcode="+pn.hashCode()+"\">";
+ NameSuffixString = "</a>";
+ }
row[0] = pn;
row[1] = "<input type=\"checkbox\"
name=\"delete_node_"+pn.hashCode()+"\" />";
row[2] = status;
- row[3] = HTMLEncoder.encode(pn.getName());
+ row[3] =
NamePrefixString+HTMLEncoder.encode(pn.getName())+NameSuffixString;
row[4] = ( pn.getDetectedPeer() != null ?
HTMLEncoder.encode(pn.getDetectedPeer().toString()) : "(address unknown)" ) +
avgPingTimeString;
row[5] =
VersionPrefixString+HTMLEncoder.encode(pn.getVersion())+VersionSuffixString;
row[6] = new
Double(pn.getLocation().getValue());
row[7] = backoff/1000 + "/" +
pn.getRoutingBackoffLength()/1000+lastBackoffReasonOutputString;
if (idle == -1) row[8] = " ";
else row[8] = new Long((now - idle) / 60000);
-
+ row[9] = HTMLEncoder.encode(pn.getName());
}
// Sort array
@@ -180,6 +186,8 @@
Object[] row = rows[i];
buf2.append("<tr>");
for(int j=1;j<row.length;j++) { // skip index
0 as it's the PeerNode object
+ if(j == 9) // skip index 9 as it's used for
sorting purposes only
+ continue;
buf2.append("<td>"+row[j]+"</td>");
}
buf2.append("</tr>\n");
@@ -393,7 +401,7 @@
headers.put("Location", "/darknet/");
ctx.sendReplyHeaders(302, "Found", headers, null, 0);
return;
- }else{
+ } else {
this.handleGet(uri, ctx);
}
}
Modified: trunk/freenet/src/freenet/clients/http/FProxyToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2006-05-26
19:30:28 UTC (rev 8878)
+++ trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2006-05-27
00:53:10 UTC (rev 8879)
@@ -355,6 +355,9 @@
DarknetConnectionsToadlet darknetToadlet = new
DarknetConnectionsToadlet(node, client);
server.register(darknetToadlet, "/darknet/", true);
+ N2NTMToadlet n2ntmToadlet = new N2NTMToadlet(node,
client);
+ server.register(n2ntmToadlet, "/send_n2ntm/", true);
+
QueueToadlet queueToadlet = new
QueueToadlet(node.getFCPServer(), client);
server.register(queueToadlet, "/queue/", true);
Added: trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2006-05-26
19:30:28 UTC (rev 8878)
+++ trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2006-05-27
00:53:10 UTC (rev 8879)
@@ -0,0 +1,158 @@
+package freenet.clients.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Enumeration;
+
+import freenet.client.HighLevelSimpleClient;
+import freenet.io.comm.DMT;
+import freenet.io.comm.Message;
+import freenet.io.comm.NotConnectedException;
+import freenet.io.comm.PeerParseException;
+import freenet.io.comm.UdpSocketManager;
+import freenet.node.FSParseException;
+import freenet.node.Node;
+import freenet.node.PeerNode;
+import freenet.node.Version;
+import freenet.support.Bucket;
+import freenet.support.HTMLEncoder;
+import freenet.support.Logger;
+import freenet.support.MultiValueTable;
+import freenet.support.SimpleFieldSet;
+
+public class N2NTMToadlet extends Toadlet {
+
+ private Node node;
+ private UdpSocketManager usm;
+
+ protected N2NTMToadlet(Node n, HighLevelSimpleClient client) {
+ super(client);
+ this.node = n;
+ this.usm = n.getUSM();
+ }
+
+ public String supportedMethods() {
+ return "GET, POST";
+ }
+
+ public void handleGet(URI uri, ToadletContext ctx) throws
ToadletContextClosedException, IOException, RedirectException {
+
+ HTTPRequest request = new HTTPRequest(uri, null, ctx);
+ StringBuffer buf = new StringBuffer(1024);
+ if (request.isParameterSet("peernode_hashcode")) {
+ ctx.getPageMaker().makeHead(buf, "Send Node To Node Text Message");
+ String peernode_name = null;
+ String input_hashcode_string = request.getParam("peernode_hashcode");
+ int input_hashcode = -1;
+ try {
+ input_hashcode = (new Integer(input_hashcode_string)).intValue();
+ } catch (NumberFormatException e) {
+ // ignore here, handle below
+ }
+ if(input_hashcode != -1) {
+ PeerNode[] peerNodes = node.getDarknetConnections();
+ for(int i = 0; i < peerNodes.length; i++) {
+ int peer_hashcode = peerNodes[i].hashCode();
+ if(peer_hashcode == input_hashcode) {
+ peernode_name = peerNodes[i].getName();
+ break;
+ }
+ }
+ }
+ if(peernode_name == null) {
+ buf.append("PeerNode.hashCode '"+input_hashcode_string+"' not
found.<br /><br />\n");
+ buf.append("<a href=\"/darknet/\">Back to Darknet page</a>\n");
+ ctx.getPageMaker().makeTail(buf);
+ this.writeReply(ctx, 200, "text/html", "OK", buf.toString());
+ return;
+ }
+ buf.append("<b>Sending Node To Node Text Message to
"+HTMLEncoder.encode(peernode_name)+":</b><br />\n");
+ buf.append("<form action=\".\" method=\"post\"
enctype=\"multipart/form-data\">\n");
+ buf.append("<input type=\"hidden\" name=\"hashcode\"
value=\""+input_hashcode_string+"\" />\n");
+ buf.append("<textarea id=\"n2ntmtext\" name=\"message\" rows=\"8\"
cols=\"74\"></textarea><br />\n");
+ buf.append("<input type=\"submit\" name=\"send\" value=\"Send message to
"+HTMLEncoder.encode(peernode_name)+"\" />\n");
+ buf.append("</form>\n");
+ ctx.getPageMaker().makeTail(buf);
+ this.writeReply(ctx, 200, "text/html", "OK", buf.toString());
+ return;
+ }
+ MultiValueTable headers = new MultiValueTable();
+ headers.put("Location", "/darknet/");
+ ctx.sendReplyHeaders(302, "Found", headers, null, 0);
+ }
+
+ public void handlePost(URI uri, Bucket data, ToadletContext ctx) throws
ToadletContextClosedException, IOException, RedirectException {
+ if(data.size() > 1024*1024) {
+ this.writeReply(ctx, 400, "text/plain", "Too big", "Too much data,
darknet toadlet limited to 1MB");
+ return;
+ }
+
+ HTTPRequest request = new HTTPRequest(uri, data, ctx);
+ StringBuffer buf = new StringBuffer(1024);
+
+ if (request.isPartSet("send")) {
+ String message = request.getPartAsString("message", 2000);
+ message = message.trim();
+ PeerNode pn = null;
+ String input_hashcode_string = request.getPartAsString("hashcode", 2000);
+ request.freeParts();
+ input_hashcode_string = input_hashcode_string.trim();
+ int input_hashcode = -1;
+ try {
+ input_hashcode = (new Integer(input_hashcode_string)).intValue();
+ } catch (NumberFormatException e) {
+ // ignore here, handle below
+ }
+ if(input_hashcode != -1) {
+ PeerNode[] peerNodes = node.getDarknetConnections();
+ for(int i = 0; i < peerNodes.length; i++) {
+ int peer_hashcode = peerNodes[i].hashCode();
+ if(peer_hashcode == input_hashcode) {
+ pn = peerNodes[i];
+ break;
+ }
+ }
+ }
+ if(pn == null) {
+ buf.append("PeerNode.hashCode '"+input_hashcode_string+"' not
found.<br /><br />\n");
+ buf.append("<a href=\"/darknet/\">Back to Darknet page</a>\n");
+ ctx.getPageMaker().makeTail(buf);
+ this.writeReply(ctx, 200, "text/html", "OK", buf.toString());
+ return;
+ }
+ try {
+ Message n2ntm =
DMT.createNodeToNodeTextMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT,
node.getMyName(), pn.getName(), message);
+ if(pn == null) {
+ buf.append("PeerNode.hashCode '"+request.getParam("hashcode")+"' not
found.<br /><br />\n");
+ } else if(!pn.isConnected()) {
+ buf.append("Peer '"+HTMLEncoder.encode(pn.getName())+"' is not
connected. Not sending N2NTM.<br /><br />\n");
+ } else if(pn.getPeerNodeStatus() ==
Node.PEER_NODE_STATUS_ROUTING_BACKED_OFF) {
+ buf.append("Peer '"+HTMLEncoder.encode(pn.getName())+"' is \"backed
off\". N2NTM receipt may be significantly delayed.<br /><br />\n");
+ usm.send(pn, n2ntm);
+ buf.append("Message should be on it's way.<br /><br />\n");
+ } else {
+ buf.append("Sending N2NTM to peer
'"+HTMLEncoder.encode(pn.getName())+"'.<br /><br />\n");
+ usm.send(pn, n2ntm);
+ buf.append("Message should be on it's way.<br /><br />\n");
+ }
+ } catch (NotConnectedException e) {
+ buf.append("Got NotConnectedException sending message to Peer
'"+HTMLEncoder.encode(pn.getName())+"'. Can't send N2NTM.<br /><br />\n");
+ Logger.error(this, "Caught NotConnectedException while trying to send
n2ntm: "+e);
+ }
+ buf.append("<a href=\"/darknet/\">Back to Darknet page</a>\n");
+ ctx.getPageMaker().makeTail(buf);
+ this.writeReply(ctx, 200, "text/html", "OK", buf.toString());
+ return;
+ }
+ MultiValueTable headers = new MultiValueTable();
+ headers.put("Location", "/darknet/");
+ ctx.sendReplyHeaders(302, "Found", headers, null, 0);
+ }
+}
Modified: trunk/freenet/src/freenet/io/comm/DMT.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/DMT.java 2006-05-26 19:30:28 UTC (rev
8878)
+++ trunk/freenet/src/freenet/io/comm/DMT.java 2006-05-27 00:53:10 UTC (rev
8879)
@@ -84,6 +84,10 @@
public static final String PUBKEY_HASH = "pubkeyHash";
public static final String NEED_PUB_KEY = "needPubKey";
public static final String PUBKEY_AS_BYTES = "pubkeyAsBytes";
+ public static final String SOURCE_NODENAME = "sourceNodename";
+ public static final String TARGET_NODENAME = "targetNodename";
+ public static final String NODE_TO_NODE_MESSAGE_TYPE =
"nodeToNodeMessageType";
+ public static final String NODE_TO_NODE_MESSAGE_TEXT =
"nodeToNodeMessageText";
//Diagnostic
public static final MessageType ping = new MessageType("ping") {{
@@ -343,6 +347,23 @@
return msg;
}
+ // Node-To-Node Instant Message
+ public static final MessageType nodeToNodeTextMessage = new
MessageType("nodeToNodeTextMessage", false) {{
+ addField(NODE_TO_NODE_MESSAGE_TYPE, Integer.class);
+ addField(SOURCE_NODENAME, String.class);
+ addField(TARGET_NODENAME, String.class);
+ addField(NODE_TO_NODE_MESSAGE_TEXT, String.class);
+ }};
+
+ public static final Message createNodeToNodeTextMessage(int type, String
source, String target, String message) {
+ Message msg = new Message(nodeToNodeTextMessage);
+ msg.set(NODE_TO_NODE_MESSAGE_TYPE, type);
+ msg.set(SOURCE_NODENAME, source);
+ msg.set(TARGET_NODENAME, target);
+ msg.set(NODE_TO_NODE_MESSAGE_TEXT, message);
+ return msg;
+ }
+
// FNP messages
public static final MessageType FNPCHKDataRequest = new
MessageType("FNPCHKDataRequest") {{
addField(UID, Long.class);
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-05-26 19:30:28 UTC (rev
8878)
+++ trunk/freenet/src/freenet/node/Node.java 2006-05-27 00:53:10 UTC (rev
8879)
@@ -92,6 +92,7 @@
import freenet.node.useralerts.BuildOldAgeUserAlert;
import freenet.node.useralerts.IPUndetectedUserAlert;
import freenet.node.useralerts.MeaningfulNodeNameUserAlert;
+import freenet.node.useralerts.N2NTMUserAlert;
import freenet.node.useralerts.UserAlertManager;
import freenet.pluginmanager.PluginManager;
import freenet.store.BerkeleyDBFreenetStore;
@@ -536,6 +537,7 @@
public static final int PEER_NODE_STATUS_TOO_NEW = 3;
public static final int PEER_NODE_STATUS_TOO_OLD = 4;
public static final int PEER_NODE_STATUS_DISCONNECTED = 5;
+ public static final int N2N_TEXT_MESSAGE_TYPE_USERALERT = 1;
public final long bootID;
public final long startupTime;
@@ -2889,4 +2891,30 @@
nextPeerNodeStatusLogTime = now + peerNodeStatusLogInterval;
}
}
+
+ /**
+ * Handle a received node to node text message
+ */
+ public void receivedNodeToNodeTextMessage(Message m) {
+ PeerNode source = (PeerNode)m.getSource();
+ int type = ((Integer)
m.getObject(DMT.NODE_TO_NODE_MESSAGE_TYPE)).intValue();
+ if(type == Node.N2N_TEXT_MESSAGE_TYPE_USERALERT) {
+ String source_nodename = (String) m.getObject(DMT.SOURCE_NODENAME);
+ String target_nodename = (String) m.getObject(DMT.TARGET_NODENAME);
+ String text = (String) m.getObject(DMT.NODE_TO_NODE_MESSAGE_TEXT);
+ Logger.normal(this, "Received N2NTM from '"+source_nodename+"' to
'"+target_nodename+"': "+text);
+ N2NTMUserAlert userAlert = new N2NTMUserAlert(source_nodename,
target_nodename, text);
+ alerts.register(userAlert);
+ } else {
+ Logger.error(this, "Received unknown node to node message type
'"+type+"' from "+source.getPeer());
+ }
+ }
+
+ public String getMyName() {
+ return myName;
+ }
+
+ public UdpSocketManager getUSM() {
+ return usm;
+ }
}
Modified: trunk/freenet/src/freenet/node/NodeDispatcher.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeDispatcher.java 2006-05-26 19:30:28 UTC
(rev 8878)
+++ trunk/freenet/src/freenet/node/NodeDispatcher.java 2006-05-27 00:53:10 UTC
(rev 8879)
@@ -40,7 +40,8 @@
public boolean handleMessage(Message m) {
PeerNode source = (PeerNode)m.getSource();
Logger.minor(this, "Dispatching "+m);
- if(m.getSpec() == DMT.FNPPing) {
+ MessageType spec = m.getSpec();
+ if(spec == DMT.FNPPing) {
// Send an FNPPong
Message reply = DMT.createFNPPong(m.getInt(DMT.PING_SEQNO));
try {
@@ -50,7 +51,6 @@
}
return true;
}
- MessageType spec = m.getSpec();
if(spec == DMT.FNPLocChangeNotification) {
double newLoc = m.getDouble(DMT.LOCATION);
source.updateLocation(newLoc);
@@ -94,6 +94,9 @@
node.redetectAddress();
} else if(spec == DMT.FNPVoid) {
return true;
+ } else if(spec == DMT.nodeToNodeTextMessage) {
+ node.receivedNodeToNodeTextMessage(m);
+ return true;
}
return false;
}
Added: trunk/freenet/src/freenet/node/useralerts/N2NTMUserAlert.java
===================================================================
--- trunk/freenet/src/freenet/node/useralerts/N2NTMUserAlert.java
2006-05-26 19:30:28 UTC (rev 8878)
+++ trunk/freenet/src/freenet/node/useralerts/N2NTMUserAlert.java
2006-05-27 00:53:10 UTC (rev 8879)
@@ -0,0 +1,45 @@
+package freenet.node.useralerts;
+
+import freenet.support.HTMLEncoder;
+
+// Node To Node Text Message User Alert
+public class N2NTMUserAlert implements UserAlert {
+ private boolean isValid=true;
+ public int lastGoodVersion = 0;
+ private String source_nodename;
+ private String target_nodename;
+ private String message_text;
+
+ public N2NTMUserAlert(String source, String target, String message) {
+ this.source_nodename = source;
+ this.target_nodename = target;
+ this.message_text = message;
+ isValid=true;
+ }
+
+ public boolean userCanDismiss() {
+ return true;
+ }
+
+ public String getTitle() {
+ return "Node To Node Text Message";
+ }
+
+ public String getText() {
+ String s;
+ s = "You, as nodename
'"+HTMLEncoder.encode(target_nodename)+"', have received a node to node text
message from nodename '"+HTMLEncoder.encode(source_nodename)+"':<br /><br
/>"+HTMLEncoder.encode(message_text);
+ return s;
+ }
+
+ public short getPriorityClass() {
+ return UserAlert.MINOR;
+ }
+
+ public boolean isValid() {
+ return isValid;
+ }
+
+ public void isValid(boolean b){
+ if(userCanDismiss()) isValid=b;
+ }
+}