Author: toad
Date: 2006-03-15 19:53:25 +0000 (Wed, 15 Mar 2006)
New Revision: 8256

Added:
   trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java
Modified:
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/TextModeClientInterface.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/node/fcp/ClientGet.java
   trunk/freenet/src/freenet/node/fcp/FCPServer.java
Log:
536:
Make TextModeClientInterface capable of running on either stdin/stdout, or a 
socket server.
The latter is on by default, the former is not.
Nextgens did a lot of the work for this.

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2006-03-15 19:16:28 UTC (rev 
8255)
+++ trunk/freenet/src/freenet/node/Node.java    2006-03-15 19:53:25 UTC (rev 
8256)
@@ -70,9 +70,6 @@
 import freenet.keys.SSKVerifyException;
 import freenet.node.fcp.FCPServer;
 import freenet.pluginmanager.PluginManager;
-import freenet.pluginmanager.PluginRespirator;
-import freenet.pluginmanager.PproxyToadlet;
-import freenet.snmplib.SNMPAgent;
 import freenet.snmplib.SNMPStarter;
 import freenet.store.BerkeleyDBFreenetStore;
 import freenet.store.FreenetStore;
@@ -229,6 +226,7 @@
        static final int EXIT_BAD_TEMP_DIR = 16;
        static final int EXIT_COULD_NOT_START_FCP = 17;
        static final int EXIT_COULD_NOT_START_FPROXY = 18;
+       static final int EXIT_COULD_NOT_START_TMCI = 19;


     public final long bootID;
@@ -251,7 +249,8 @@
     public final ClientRequestScheduler chkPutScheduler;
     public final ClientRequestScheduler sskFetchScheduler;
     public final ClientRequestScheduler sskPutScheduler;
-    TextModeClientInterface tmci;
+    TextModeClientInterfaceServer tmci;
+    TextModeClientInterface directTMCI;
     FCPServer fcpServer;
     FproxyToadlet fproxyServlet;
     private SymlinkerToadlet symlinkerToadlet;
@@ -900,7 +899,12 @@
         // Start services

         // TMCI
-        TextModeClientInterface.maybeCreate(this, config);
+        try{
+               TextModeClientInterfaceServer.maybeCreate(this, config);
+        } catch (IOException e) {
+                       e.printStackTrace();
+                       throw new NodeInitException(EXIT_COULD_NOT_START_TMCI, 
"Could not start TMCI: "+e);
+               }

         // Fproxy
         // FIXME this is a hack, the real way to do this is plugins
@@ -2073,6 +2077,10 @@
        public SimpleToadletServer getToadletContainer() {
                return toadletContainer;
        }
+       
+       public TextModeClientInterfaceServer getTextModeClientInterface(){
+               return tmci;
+       }

        public void setFproxy(FproxyToadlet fproxy) {
                this.fproxyServlet = fproxy;
@@ -2081,8 +2089,26 @@
        public void setFCPServer(FCPServer fcp) {
                this.fcpServer = fcp;
        }
+       
+       public void exit(){
+               config.store();
+        System.out.println("Goodbye.");
+        System.exit(0);
+       }

        public SymlinkerToadlet getSymlinkerToadlet() {
                return symlinkerToadlet;
        }
+
+       public void setTMCI(TextModeClientInterfaceServer server) {
+               this.tmci = server;
+       }
+
+       public TextModeClientInterface getDirectTMCI() {
+               return directTMCI;
+       }
+       
+       public void setDirectTMCI(TextModeClientInterface i) {
+               this.directTMCI = i;
+       }
 }

Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-03-15 
19:16:28 UTC (rev 8255)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-03-15 
19:53:25 UTC (rev 8256)
@@ -7,13 +7,16 @@
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.HashMap;
 import java.util.Hashtable;
-import java.util.Iterator;

 import freenet.client.ClientMetadata;
 import freenet.client.DefaultMIMETypes;
@@ -22,12 +25,6 @@
 import freenet.client.HighLevelSimpleClient;
 import freenet.client.InsertBlock;
 import freenet.client.InserterException;
-import freenet.client.Metadata;
-import freenet.client.events.EventDumper;
-import freenet.config.BooleanCallback;
-import freenet.config.Config;
-import freenet.config.InvalidConfigValueException;
-import freenet.config.SubConfig;
 import freenet.crypt.RandomSource;
 import freenet.io.comm.Peer;
 import freenet.io.comm.PeerParseException;
@@ -55,71 +52,103 @@
     final HighLevelSimpleClient client;
     final Hashtable streams;
     final File downloadsDir;
+    final InputStream in;
+    final OutputStream out;

-    TextModeClientInterface(Node n) {
-        this.n = n;
-        client = n.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS);
-        client.addGlobalHook(new EventDumper());
-        this.r = n.random;
-        streams = new Hashtable();
-        new Thread(this, "Text mode client interface").start();
-        this.downloadsDir = n.downloadDir;
+    public TextModeClientInterface(TextModeClientInterfaceServer server, 
InputStream in, OutputStream out) {
+       this.n = server.n;
+       this.r = server.r;
+       this.client = server.client;
+       this.streams = new Hashtable();
+       this.downloadsDir = server.downloadsDir;
+       this.in = in;
+       this.out = out;
+       }
+
+    public TextModeClientInterface(Node n, HighLevelSimpleClient c, File 
downloadDir, InputStream in, OutputStream out) {
+       this.n = n;
+       this.r = n.random;
+       this.client = c;
+       this.streams = new Hashtable();
+       this.downloadsDir = downloadDir;
+       this.in = in;
+       this.out = out;
     }

-    /**
-     * Read commands, run them
-     */
     public void run() {
-       printHeader();
-        // Read command, and data
-        BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
+       try {
+               realRun();
+       } catch (IOException e) {
+               Logger.minor(this, "Caught "+e, e);
+       } catch (Throwable t) {
+               Logger.error(this, "Caught "+t, t);
+       }
+    }
+    
+    public void realRun() throws IOException {
+               printHeader(out);
+
+               BufferedReader reader = new BufferedReader(new 
InputStreamReader(in));
         while(true) {
             try {
-                processLine(reader);
+                processLine(reader,out);
+            } catch (IOException e) {
+               Logger.error(this, "Socket error: "+e, e);
+               return;
             } catch (Throwable t) {
                 Logger.error(this, "Caught "+t, t);
                 System.out.println("Caught: "+t);
-                t.printStackTrace();
+                StringWriter sw = new StringWriter();
+                t.printStackTrace(new PrintWriter(sw));
+                try {
+                                       out.write(sw.toString().getBytes());
+                               } catch (IOException e) {
+                       Logger.error(this, "Socket error: "+e, e);
+                                       return;
+                               }
             }
         }
     }
-
-    private void printHeader() {
-        System.out.println("Freenet 0.7 Trivial Node Test Interface");
-        System.out.println("---------------------------------------");
-        System.out.println();
-        System.out.println("Build "+Version.buildNumber());
-        System.out.println("Enter one of the following commands:");
-        System.out.println("GET:<Freenet key> - Fetch a key");
-        System.out.println("PUT:\n<text, until a . on a line by itself> - 
Insert the document and return the key.");
-        System.out.println("PUT:<text> - Put a single line of text to a CHK 
and return the key.");
-        System.out.println("GETCHK:\n<text, until a . on a line by itself> - 
Get the key that would be returned if the document was inserted.");
-        System.out.println("GETCHK:<text> - Get the key that would be returned 
if the line was inserted.");
-        System.out.println("PUTFILE:<filename> - Put a file from disk.");
-        System.out.println("GETFILE:<filename> - Fetch a key and put it in a 
file. If the key includes a filename we will use it but we will not overwrite 
local files.");
-        System.out.println("GETCHKFILE:<filename> - Get the key that would be 
returned if we inserted the file.");
-        System.out.println("PUTDIR:<path>[#<defaultfile>] - Put the entire 
directory from disk.");
-        System.out.println("GETCHKDIR:<path>[#<defaultfile>] - Get the key 
that would be returned if we'd put the entire directory from disk.");
-        System.out.println("MAKESSK - Create an SSK keypair.");
-        System.out.println("PUTSSK:<insert uri>;<url to redirect to> - Insert 
an SSK redirect to a file already inserted.");
-        System.out.println("PUTSSKDIR:<insert uri>#<path>[#<defaultfile>] - 
Insert an entire directory to an SSK.");
-        System.out.println("PLUGLOAD: - Load plugin. (use \"PLUGLOAD:?\" for 
more info)");
-        //System.out.println("PLUGLOAD: <pkg.classname>[(@<URI to 
jarfile.jar>|<<URI to file containing real URI>|* (will load from freenets 
pluginpool))] - Load plugin.");
-        System.out.println("PLUGLIST - List all loaded plugins.");
-        System.out.println("PLUGKILL: <pluginID> - Unload the plugin with the 
given ID (see PLUGLIST).");
-//        System.out.println("PUBLISH:<name> - create a publish/subscribe 
stream called <name>");
-//        System.out.println("PUSH:<name>:<text> - publish a single line of 
text to the stream named");
-//        System.out.println("SUBSCRIBE:<key> - subscribe to a 
publish/subscribe stream by key");
-        System.out.println("CONNECT:<filename|URL> - connect to a node from 
its ref in a file/url.");
-        System.out.println("CONNECT:\n<noderef including an End on a line by 
itself> - enter a noderef directly.");
-        System.out.println("DISCONNECT:<ip:port> - disconnect from a node by 
providing it's ip+port or name");
-        System.out.println("NAME:<new node name> - change the node's name.");
-//        System.out.println("SUBFILE:<filename> - append all data received 
from subscriptions to a file, rather than sending it to stdout.");
-//        System.out.println("SAY:<text> - send text to the last 
created/pushed stream");
-        System.out.println("STATUS - display some status information on the 
node including its reference and connections.");
-        System.out.println("QUIT - exit the program");
+    
+       private void printHeader(OutputStream s) throws IOException {
+       StringBuffer sb = new StringBuffer();
+       
+        sb.append("Freenet 0.7 Trivial Node Test Interface\n");
+        sb.append("---------------------------------------\n");
+        sb.append("Build "+Version.buildNumber());
+        sb.append("Enter one of the following commands:\n");
+        sb.append("GET:<Freenet key> - Fetch a key\n");
+        sb.append("PUT:\n<text, until a . on a line by itself> - Insert the 
document and return the key.\n");
+        sb.append("PUT:<text> - Put a single line of text to a CHK and return 
the key.\n");
+        sb.append("GETCHK:\n<text, until a . on a line by itself> - Get the 
key that would be returned if the document was inserted.\n");
+        sb.append("GETCHK:<text> - Get the key that would be returned if the 
line was inserted.\n");
+        sb.append("PUTFILE:<filename> - Put a file from disk.\n");
+        sb.append("GETFILE:<filename> - Fetch a key and put it in a file. If 
the key includes a filename we will use it but we will not overwrite local 
files.\n");
+        sb.append("GETCHKFILE:<filename> - Get the key that would be returned 
if we inserted the file.\n");
+        sb.append("PUTDIR:<path>[#<defaultfile>] - Put the entire directory 
from disk.\n");
+        sb.append("GETCHKDIR:<path>[#<defaultfile>] - Get the key that would 
be returned if we'd put the entire directory from disk.\n");
+        sb.append("MAKESSK - Create an SSK keypair.\n");
+        sb.append("PUTSSK:<insert uri>;<url to redirect to> - Insert an SSK 
redirect to a file already inserted.\n");
+        sb.append("PUTSSKDIR:<insert uri>#<path>[#<defaultfile>] - Insert an 
entire directory to an SSK.\n");
+        sb.append("PLUGLOAD: - Load plugin. (use \"PLUGLOAD:?\" for more 
info)\n");
+        //sb.append("PLUGLOAD: <pkg.classname>[(@<URI to jarfile.jar>|<<URI to 
file containing real URI>|* (will load from freenets pluginpool))] - Load 
plugin.\n");
+        sb.append("PLUGLIST - List all loaded plugins.\n");
+        sb.append("PLUGKILL: <pluginID> - Unload the plugin with the given ID 
(see PLUGLIST).\n");
+//        sb.append("PUBLISH:<name> - create a publish/subscribe stream called 
<name>\n");
+//        sb.append("PUSH:<name>:<text> - publish a single line of text to the 
stream named\n");
+//        sb.append("SUBSCRIBE:<key> - subscribe to a publish/subscribe stream 
by key\n");
+        sb.append("CONNECT:<filename|URL> - connect to a node from its ref in 
a file/url.\n");
+        sb.append("CONNECT:\n<noderef including an End on a line by itself> - 
enter a noderef directly.\n");
+        sb.append("DISCONNECT:<ip:port> - disconnect from a node by providing 
it's ip+port or name\n");
+        sb.append("NAME:<new node name> - change the node's name.\n");
+//        sb.append("SUBFILE:<filename> - append all data received from 
subscriptions to a file, rather than sending it to stdout.\n");
+//        sb.append("SAY:<text> - send text to the last created/pushed 
stream\n");
+        sb.append("STATUS - display some status information on the node 
including its reference and connections.\n");
+        sb.append("QUIT - exit the program\n");
         if(n.testnetEnabled) {
-               System.out.println("WARNING: TESTNET MODE ENABLED. YOU HAVE NO 
ANONYMITY.");
+               sb.append("WARNING: TESTNET MODE ENABLED. YOU HAVE NO 
ANONYMITY.\n");
+        
+        s.write(sb.toString().getBytes());
         }
     }

@@ -127,11 +156,13 @@
      * Process a single command.
      * @throws IOException If we could not write the data to stdout.
      */
-    private void processLine(BufferedReader reader) throws IOException {
+    private void processLine(BufferedReader reader, OutputStream out) throws 
IOException {
         String line;
+        StringBuffer outsb = new StringBuffer();
         try {
             line = reader.readLine();
         } catch (IOException e) {
+            outsb.append("Bye... ("+e+")");
             System.err.println("Bye... ("+e+")");
             return;
         }
@@ -152,17 +183,18 @@
                 uri = new FreenetURI(key);
                 Logger.normal(this, "Key: "+uri);
             } catch (MalformedURLException e2) {
-                System.out.println("Malformed URI: "+key+" : "+e2);
+                outsb.append("Malformed URI: "+key+" : "+e2);
                 return;
             }
             try {
                                FetchResult result = client.fetch(uri);
                                ClientMetadata cm = result.getMetadata();
-                               System.out.println("Content MIME type: 
"+cm.getMIMEType());
+                               outsb.append("Content MIME type: 
"+cm.getMIMEType());
                                Bucket data = result.asBucket();
                                // FIXME limit it above
                                if(data.size() > 32*1024) {
                                        System.err.println("Data is more than 
32K: "+data.size());
+                                       outsb.append("Data is more than 32K: 
"+data.size());
                                        return;
                                }
                                byte[] dataBytes = 
BucketTools.toByteArray(data);
@@ -175,15 +207,15 @@
                                }
                                if(evil) {
                                        System.err.println("Data may contain 
escape codes which could cause the terminal to run arbitrary commands! Save it 
to a file if you must with GETFILE:");
-                                       return;
+                                       outsb.append("Data may contain escape 
codes which could cause the terminal to run arbitrary commands! Save it to a 
file if you must with GETFILE:");
+                                               return;
                                }
-                               System.out.println("Data:\n");
-                               System.out.println(new String(dataBytes));
-                               System.out.println();
+                               outsb.append("Data:\n");
+                               outsb.append(new String(dataBytes));
                        } catch (FetchException e) {
-                               System.out.println("Error: "+e.getMessage());
+                               outsb.append("Error: "+e.getMessage());
                if(e.getMode() == e.SPLITFILE_ERROR && e.errorCodes != null) {
-                       System.out.println(e.errorCodes.toVerboseString());
+                       outsb.append(e.errorCodes.toVerboseString());
                }
                        }
         } else if(uline.startsWith("GETFILE:")) {
@@ -198,14 +230,14 @@
             try {
                 uri = new FreenetURI(key);
             } catch (MalformedURLException e2) {
-                System.out.println("Malformed URI: "+key+" : "+e2);
+                outsb.append("Malformed URI: "+key+" : "+e2);
                 return;
             }
             try {
                long startTime = System.currentTimeMillis();
                                FetchResult result = client.fetch(uri);
                                ClientMetadata cm = result.getMetadata();
-                               System.out.println("Content MIME type: 
"+cm.getMIMEType());
+                               outsb.append("Content MIME type: 
"+cm.getMIMEType());
                                Bucket data = result.asBucket();
                 // Now calculate filename
                 String fnam = uri.getDocName();
@@ -218,7 +250,7 @@
                 }
                 File f = new File(downloadsDir, fnam);
                 if(f.exists()) {
-                    System.out.println("File exists already: "+fnam);
+                    outsb.append("File exists already: "+fnam);
                     fnam = "freenet-"+System.currentTimeMillis()+"-"+fnam;
                 }
                 FileOutputStream fos = null;
@@ -226,9 +258,9 @@
                     fos = new FileOutputStream(f);
                     BucketTools.copyTo(data, fos, Long.MAX_VALUE);
                     fos.close();
-                    System.out.println("Written to "+fnam);
+                    outsb.append("Written to "+fnam);
                 } catch (IOException e) {
-                    System.out.println("Could not write file: caught "+e);
+                    outsb.append("Could not write file: caught "+e);
                     e.printStackTrace();
                 } finally {
                     if(fos != null) try {
@@ -240,16 +272,15 @@
                 long endTime = System.currentTimeMillis();
                 long sz = data.size();
                 double rate = 1000.0 * sz / (endTime-startTime);
-                System.out.println("Download rate: "+rate+" bytes / second");
+                outsb.append("Download rate: "+rate+" bytes / second");
                        } catch (FetchException e) {
-                               System.out.println("Error: "+e.getMessage());
+                               outsb.append("Error: "+e.getMessage());
                if(e.getMode() == e.SPLITFILE_ERROR && e.errorCodes != null) {
-                       System.out.println(e.errorCodes.toVerboseString());
+                       outsb.append(e.errorCodes.toVerboseString());
                }
                        }
         } else if(uline.startsWith("QUIT")) {
-            System.out.println("Goodbye.");
-            System.exit(0);
+            n.exit();
         } else if(uline.startsWith("PUT:") || (getCHKOnly = 
uline.startsWith("GETCHK:"))) {
             // Just insert to local store
                if(getCHKOnly)
@@ -277,17 +308,17 @@
             try {
                uri = client.insert(block, getCHKOnly);
             } catch (InserterException e) {
-               System.out.println("Error: "+e.getMessage());
+               outsb.append("Error: "+e.getMessage());
                if(e.uri != null)
-                       System.out.println("URI would have been: "+e.uri);
+                       outsb.append("URI would have been: "+e.uri);
                int mode = e.getMode();
                if(mode == InserterException.FATAL_ERRORS_IN_BLOCKS || mode == 
InserterException.TOO_MANY_RETRIES_IN_BLOCKS) {
-                       System.out.println("Splitfile-specific 
error:\n"+e.errorCodes.toVerboseString());
+                       outsb.append("Splitfile-specific 
error:\n"+e.errorCodes.toVerboseString());
                }
                return;
             }

-            System.out.println("URI: "+uri);
+            outsb.append("URI: "+uri);
             
////////////////////////////////////////////////////////////////////////////////
         } else if(uline.startsWith("PUTDIR:") || 
(uline.startsWith("PUTSSKDIR")) || (getCHKOnly = 
uline.startsWith("GETCHKDIR:"))) {
                // TODO: Check for errors?
@@ -299,13 +330,15 @@
                        ssk = true;
                } else if(uline.startsWith("GETCHKDIR:"))
                        line = line.substring(("GETCHKDIR:").length());
-               else
+               else {
                        System.err.println("Impossible");
+                       outsb.append("Impossible");
+               }

                line = line.trim();

                if(line.length() < 1) {
-                       printHeader();
+                       printHeader(out);
                        return;
                }

@@ -345,19 +378,19 @@
                        try {
                                uri = client.insertManifest(insertURI, 
bucketsByName, defaultFile);
                                uri = uri.addMetaStrings(new String[] { "" });
-                       
System.out.println("=======================================================");
-                   System.out.println("URI: "+uri);
-                       
System.out.println("=======================================================");
+                       
outsb.append("=======================================================");
+                   outsb.append("URI: "+uri);
+                       
outsb.append("=======================================================");
                        } catch (InserterException e) {
-               System.out.println("Finished insert but: "+e.getMessage());
+               outsb.append("Finished insert but: "+e.getMessage());
                if(e.uri != null) {
                        uri = e.uri;
                                uri = uri.addMetaStrings(new String[] { "" });
-                       System.out.println("URI would have been: "+uri);
+                       outsb.append("URI would have been: "+uri);
                }
                if(e.errorCodes != null) {
-                       System.out.println("Splitfile errors breakdown:");
-                       System.out.println(e.errorCodes.toVerboseString());
+                       outsb.append("Splitfile errors breakdown:");
+                       outsb.append(e.errorCodes.toVerboseString());
                }
                Logger.error(this, "Caught "+e, e);
                        }
@@ -374,7 +407,7 @@
             while(line.length() > 0 && line.charAt(line.length()-1) == ' ')
                 line = line.substring(0, line.length()-2);
             File f = new File(line);
-            System.out.println("Attempting to read file "+line);
+            outsb.append("Attempting to read file "+line);
             long startTime = System.currentTimeMillis();
             try {
                if(!(f.exists() && f.canRead())) {
@@ -383,7 +416,7 @@

                // Guess MIME type
                String mimeType = DefaultMIMETypes.guessMIMEType(line);
-               System.out.println("Using MIME type: "+mimeType);
+               outsb.append("Using MIME type: "+mimeType);
                if(mimeType.equals(DefaultMIMETypes.DEFAULT_MIME_TYPE))
                        mimeType = ""; // don't need to override it

@@ -396,74 +429,73 @@
                // FIXME depends on CHK's still being renamable
                 //uri = uri.setDocName(f.getName());

-                System.out.println("URI: "+uri);
+                outsb.append("URI: "+uri);
                long endTime = System.currentTimeMillis();
                 long sz = f.length();
                 double rate = 1000.0 * sz / (endTime-startTime);
-                System.out.println("Upload rate: "+rate+" bytes / second");
+                outsb.append("Upload rate: "+rate+" bytes / second");
             } catch (FileNotFoundException e1) {
-                System.out.println("File not found");
+                outsb.append("File not found");
             } catch (InserterException e) {
-               System.out.println("Finished insert but: "+e.getMessage());
+               outsb.append("Finished insert but: "+e.getMessage());
                if(e.uri != null) {
-                       System.out.println("URI would have been: "+e.uri);
+                       outsb.append("URI would have been: "+e.uri);
                        long endTime = System.currentTimeMillis();
                     long sz = f.length();
                     double rate = 1000.0 * sz / (endTime-startTime);
-                    System.out.println("Upload rate: "+rate+" bytes / second");
+                    outsb.append("Upload rate: "+rate+" bytes / second");
                }
                if(e.errorCodes != null) {
-                       System.out.println("Splitfile errors breakdown:");
-                       System.out.println(e.errorCodes.toVerboseString());
+                       outsb.append("Splitfile errors breakdown:");
+                       outsb.append(e.errorCodes.toVerboseString());
                }
             } catch (Throwable t) {
-                System.out.println("Insert threw: "+t);
+                outsb.append("Insert threw: "+t);
                 t.printStackTrace();
             }
         } else if(uline.startsWith("MAKESSK")) {
                InsertableClientSSK key = InsertableClientSSK.createRandom(r);
-               System.out.println("Insert URI: 
"+key.getInsertURI().toString(false));
-               System.out.println("Request URI: 
"+key.getURI().toString(false));
+               outsb.append("Insert URI: "+key.getInsertURI().toString(false));
+               outsb.append("Request URI: "+key.getURI().toString(false));
                FreenetURI insertURI = 
key.getInsertURI().setDocName("testsite");
                String fixedInsertURI = insertURI.toString(false);
-               System.out.println("Note that you MUST add a filename to the 
end of the above URLs e.g.:\n"+fixedInsertURI);
-               System.out.println("Normally you will then do PUTSSKDIR:<insert 
URI>#<directory to upload>, for 
example:\nPUTSSKDIR:"+fixedInsertURI+"#directoryToUpload/");
-               System.out.println("This will then produce a manifest site 
containing all the files, the default document can be accessed 
at\n"+insertURI.addMetaStrings(new String[] { "" }).toString(false));
+               outsb.append("Note that you MUST add a filename to the end of 
the above URLs e.g.:\n"+fixedInsertURI);
+               outsb.append("Normally you will then do PUTSSKDIR:<insert 
URI>#<directory to upload>, for 
example:\nPUTSSKDIR:"+fixedInsertURI+"#directoryToUpload/");
+               outsb.append("This will then produce a manifest site containing 
all the files, the default document can be accessed 
at\n"+insertURI.addMetaStrings(new String[] { "" }).toString(false));
         } else if(uline.startsWith("PUTSSK:")) {
                String cmd = line.substring("PUTSSK:".length());
                cmd = cmd.trim();
                if(cmd.indexOf(';') <= 0) {
-                       System.out.println("No target URI provided.");
-                       System.out.println("PUTSSK:<insert uri>;<url to 
redirect to>");
+                       outsb.append("No target URI provided.");
+                       outsb.append("PUTSSK:<insert uri>;<url to redirect 
to>");
                        return;
                }
                String[] split = cmd.split(";");
                String insertURI = split[0];
                String targetURI = split[1];
-               System.out.println("Insert URI: "+insertURI);
-               System.out.println("Target URI: "+targetURI);
+               outsb.append("Insert URI: "+insertURI);
+               outsb.append("Target URI: "+targetURI);
                FreenetURI insert = new FreenetURI(insertURI);
                FreenetURI target = new FreenetURI(targetURI);
                InsertableClientSSK key = InsertableClientSSK.create(insert);
-               System.out.println("Fetch URI: "+key.getURI());
+               outsb.append("Fetch URI: "+key.getURI());
                try {
                                FreenetURI result = 
client.insertRedirect(insert, target);
-                               System.out.println("Successfully inserted to 
fetch URI: "+key.getURI());
+                               outsb.append("Successfully inserted to fetch 
URI: "+key.getURI());
                        } catch (InserterException e) {
-               System.out.println("Finished insert but: "+e.getMessage());
+               outsb.append("Finished insert but: "+e.getMessage());
                Logger.normal(this, "Error: "+e, e);
                if(e.uri != null) {
-                       System.out.println("URI would have been: "+e.uri);
+                       outsb.append("URI would have been: "+e.uri);
                }
                        }

         } else if(uline.startsWith("STATUS")) {
             SimpleFieldSet fs = n.exportFieldSet();
-            System.out.println(fs.toString());
-            System.out.println();
-            System.out.println(n.getStatus());
+            outsb.append(fs.toString());
+            outsb.append(n.getStatus());
            if(Version.buildNumber()<Version.highestSeenBuild){
-                   System.out.println("The latest version is : 
"+Version.highestSeenBuild);
+                   outsb.append("The latest version is : 
"+Version.highestSeenBuild);
            }
         } else if(uline.startsWith("CONNECT:")) {
             String key = line.substring("CONNECT:".length());
@@ -476,13 +508,13 @@
             if(key.length() > 0) {
                 // Filename
                BufferedReader in;
-                System.out.println("Trying to connect to noderef in "+key);
+                outsb.append("Trying to connect to noderef in "+key);
                 File f = new File(key);
                 if (f.isFile()) {
-                       System.out.println("Given string seems to be a file, 
loading...");
+                       outsb.append("Given string seems to be a file, 
loading...");
                        in = new BufferedReader(new FileReader(f));
                 } else {
-                       System.out.println("Given string seems to be an URL, 
loading...");
+                       outsb.append("Given string seems to be an URL, 
loading...");
                     URL url = new URL(key);
                     URLConnection uc = url.openConnection();
                        in = new BufferedReader(
@@ -498,13 +530,13 @@
             connect(content);

         } else if(uline.startsWith("NAME:")) {
-            System.out.println("Node name currently: "+n.myName);
+            outsb.append("Node name currently: "+n.myName);
             String key = line.substring("NAME:".length());
             while(key.length() > 0 && key.charAt(0) == ' ')
                 key = key.substring(1);
             while(key.length() > 0 && key.charAt(key.length()-1) == ' ')
                 key = key.substring(0, key.length()-2);
-            System.out.println("New name: "+key);
+            outsb.append("New name: "+key);
             n.setName(key);
         } else if(uline.startsWith("DISCONNECT:")) {
                String ipAndPort = line.substring("DISCONNECT:".length());
@@ -512,31 +544,34 @@

         } else if(uline.startsWith("PLUGLOAD:")) {
                if (line.substring("PLUGLOAD:".length()).trim().equals("?")) {
-                       System.out.println("  PLUGLOAD: pkg.Class               
   - Load plugin from current classpath");                      
-                       System.out.println("  PLUGLOAD: pkg.Class at 
file:<filename>  - Load plugin from file");
-                       System.out.println("  PLUGLOAD: pkg.Class at http://... 
      - Load plugin from online file");
-                       System.out.println("  PLUGLOAD:         *@...           
   - Load plugin from manifest in given jarfile");
-                       System.out.println("");
-                       System.out.println("If the filename/url ends with 
\".url\", it" +
+                       outsb.append("  PLUGLOAD: pkg.Class                  - 
Load plugin from current classpath");                    
+                       outsb.append("  PLUGLOAD: pkg.Class at file:<filename>  
- Load plugin from file");
+                       outsb.append("  PLUGLOAD: pkg.Class at http://...       
- Load plugin from online file");
+                       outsb.append("  PLUGLOAD:         *@...              - 
Load plugin from manifest in given jarfile");
+                       outsb.append("");
+                       outsb.append("If the filename/url ends with \".url\", 
it" +
                                        " is treated as a link, meaning that 
the first line is" +
                                        " the accual URL. Else it is loaded as 
classpath and" +
                                        " the class it loaded from it (meaning 
the file could" +
                                        " be either a jar-file or a 
class-file).");
-                       System.out.println("");
-                       System.out.println("  PLUGLOAD: pkg.Class*  - Load 
newest version of plugin from 
http://downloads.freenetproject.org/alpha/plugins/";);                  
-                       System.out.println("");
+                       outsb.append("");
+                       outsb.append("  PLUGLOAD: pkg.Class*  - Load newest 
version of plugin from http://downloads.freenetproject.org/alpha/plugins/";);    
                    
+                       outsb.append("");

                } else
                        
n.pluginManager.startPlugin(line.substring("PLUGLOAD:".length()).trim());
-            //System.out.println("PLUGLOAD: <pkg.classname>[(@<URI to 
jarfile.jar>|<<URI to file containing real URI>|* (will load from freenets 
pluginpool))] - Load plugin.");
+            //outsb.append("PLUGLOAD: <pkg.classname>[(@<URI to 
jarfile.jar>|<<URI to file containing real URI>|* (will load from freenets 
pluginpool))] - Load plugin.");
         } else if(uline.startsWith("PLUGLIST")) {
-               System.out.println(n.pluginManager.dumpPlugins());
+               outsb.append(n.pluginManager.dumpPlugins());
         } else if(uline.startsWith("PLUGKILL:")) {
                
n.pluginManager.killPlugin(line.substring("PLUGKILL:".length()).trim());
         } else {
                if(uline.length() > 0)
-                       printHeader();
+                       printHeader(out);
         }
+        outsb.append("\n");
+        out.write(outsb.toString().getBytes());
+        out.flush();
     }

     /**
@@ -709,9 +744,4 @@
         return sb.toString();
     }

-       public static void maybeCreate(Node node, Config config) {
-               // FIXME make this configurable.
-               // Depends on fixing QUIT issues. (bug #81)
-               new TextModeClientInterface(node);
-       }
 }

Added: trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java   
2006-03-15 19:16:28 UTC (rev 8255)
+++ trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java   
2006-03-15 19:53:25 UTC (rev 8256)
@@ -0,0 +1,232 @@
+package freenet.node;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.Hashtable;
+
+import freenet.client.HighLevelSimpleClient;
+import freenet.client.events.EventDumper;
+import freenet.config.BooleanCallback;
+import freenet.config.Config;
+import freenet.config.IntCallback;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.StringCallback;
+import freenet.config.SubConfig;
+import freenet.crypt.RandomSource;
+import freenet.support.Logger;
+
+public class TextModeClientInterfaceServer implements Runnable {
+
+    final RandomSource r;
+    final Node n;
+    final HighLevelSimpleClient client;
+    final Hashtable streams;
+    final File downloadsDir;
+    int port;
+    final String bindto;
+    boolean isEnabled;
+
+    TextModeClientInterfaceServer(Node n, HighLevelSimpleClient client, int 
port, String bindto) {
+        this.n = n;
+        this.client = client;
+        client.addGlobalHook(new EventDumper());
+        this.r = n.random;
+        streams = new Hashtable();
+        this.downloadsDir = n.downloadDir;
+        this.port=port;
+        this.bindto=bindto;
+        this.isEnabled=true;
+        n.setTMCI(this);
+        new Thread(this, "Text mode client interface").start();
+    }
+    
+       public static void maybeCreate(Node node, Config config) throws 
IOException {
+               SubConfig TMCIConfig = new SubConfig("tmci", config);
+               
+               TMCIConfig.register("enabled", true, 1, true, "Enable TMCI", 
"Whether to enable the TMCI",
+                               new TMCIEnabledCallback(node));
+               TMCIConfig.register("bindto", "127.0.0.1", 2, true, "IP address 
to bind to", "IP address to bind to",
+                               new TMCIBindtoCallback(node));
+               TMCIConfig.register("port", 2323, 1, true, "Testnet port", 
"Testnet port number",
+                       new TCMIPortNumberCallback(node));
+               TMCIConfig.register("directEnabled", false, 1, true, "Enable on 
stdout/stdin?", "Enable text mode client interface on standard input/output? 
(.enabled refers to providing a telnet-style server, this runs it over a 
socket)",
+                               new TMCIDirectEnabledCallback(node));
+               
+               boolean TMCIEnabled = TMCIConfig.getBoolean("enabled");
+               int port =  TMCIConfig.getInt("port");
+               String bind_ip = TMCIConfig.getString("bindto");
+               boolean direct = TMCIConfig.getBoolean("directEnabled");
+        HighLevelSimpleClient client = 
node.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS);
+
+               if(TMCIEnabled){
+                       new TextModeClientInterfaceServer(node, client, port, 
bind_ip);
+                       Logger.normal(node, "TMCI started on 
"+bind_ip+":"+port);
+                       System.out.println("TMCI started on "+bind_ip+":"+port);
+               }
+               else{
+                       Logger.normal(node, "Not starting TMCI as it's 
disabled");
+               }
+               
+               if(direct) {
+                       TextModeClientInterface directTMCI =
+                               new TextModeClientInterface(node, client, 
node.downloadDir, System.in, System.out);
+                       Thread t = new Thread(directTMCI, "Direct text mode 
interface");
+                       t.setDaemon(true);
+                       t.start();
+                       node.setDirectTMCI(directTMCI);
+               }
+               
+               TMCIConfig.finishedInitialization();
+       }
+
+    
+    static class TMCIEnabledCallback implements BooleanCallback {
+       
+       final Node node;
+       
+       TMCIEnabledCallback(Node n) {
+               this.node = n;
+       }
+       
+       public boolean get() {
+               return node.getTextModeClientInterface() != null;
+       }
+       
+       public void set(boolean val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               // FIXME implement - see bug #122
+               throw new InvalidConfigValueException("Cannot be updated on the 
fly");
+       }
+    }
+
+    static class TMCIDirectEnabledCallback implements BooleanCallback {
+       
+       final Node node;
+       
+       TMCIDirectEnabledCallback(Node n) {
+               this.node = n;
+       }
+       
+       public boolean get() {
+               return node.getDirectTMCI() != null;
+       }
+       
+       public void set(boolean val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               // FIXME implement - see bug #122
+               throw new InvalidConfigValueException("Cannot be updated on the 
fly");
+       }
+    }
+    
+    static class TMCIBindtoCallback implements StringCallback {
+       
+       final Node node;
+       
+       TMCIBindtoCallback(Node n) {
+               this.node = n;
+       }
+       
+       public String get() {
+               if(node.getTextModeClientInterface()!=null)
+                       return node.getTextModeClientInterface().bindto;
+               else
+                       return "127.0.0.1";
+       }
+       
+       public void set(String val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               throw new InvalidConfigValueException("Cannot be updated on the 
fly");
+       }
+    }
+
+    static class TCMIPortNumberCallback implements IntCallback{
+       
+       final Node node;
+       
+       TCMIPortNumberCallback(Node n) {
+               this.node = n;
+       }
+       
+       public int get() {
+               if(node.getTextModeClientInterface()!=null)
+                       return node.getTextModeClientInterface().port;
+               else
+                       return 2323;
+       }
+       
+       // TODO: implement it
+       public void set(int val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               node.getTextModeClientInterface().setPort(val);
+       }
+    }
+
+    /**
+     * Read commands, run them
+     */
+    public void run() {
+       while(true) {
+               int curPort = port;
+               String bindTo = this.bindto;
+               ServerSocket server;
+               try {
+                       server = new ServerSocket(curPort, 0, 
InetAddress.getByName(bindTo));
+               } catch (IOException e) {
+                       Logger.error(this, "Could not bind to TMCI port: 
"+bindto+":"+port);
+                       System.exit(-1);
+                       return;
+               }
+               try {
+                       server.setSoTimeout(1000);
+               } catch (SocketException e1) {
+                       Logger.error(this, "Could not set timeout: "+e1, e1);
+                       System.err.println("Could not start TMCI: "+e1);
+                       e1.printStackTrace();
+                       return;
+               }
+               while(isEnabled) {
+                       // Maybe something has changed?
+                               if(port != curPort) break;
+                               if(!(this.bindto.equals(bindTo))) break;
+                       try {
+                               Socket s = server.accept();
+                               InputStream in = s.getInputStream();
+                               OutputStream out = s.getOutputStream();
+                               
+                               TextModeClientInterface tmci = 
+                                       new TextModeClientInterface(this, in, 
out);
+                               
+                               Thread t = new Thread(tmci, "Text mode client 
interface handler for "+s.getPort());
+                               
+                               t.setDaemon(true);
+                               
+                               t.start();
+                               
+                       } catch (SocketTimeoutException e) {
+                               // Ignore and try again
+                       } catch (SocketException e){
+                               Logger.error(this, "Socket error : "+e, e);
+                       } catch (IOException e) {
+                               Logger.error(this, "TMCI failed to accept 
socket: "+e, e);
+                       }
+               }
+               try{
+                       server.close();
+               }catch (IOException e){
+                       Logger.error(this, "Error shuting down TMCI", e);
+               }
+       }
+    }
+
+       public void setPort(int val) {
+               port = val;
+       }
+       
+}

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-15 19:16:28 UTC (rev 
8255)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-15 19:53:25 UTC (rev 
8256)
@@ -20,7 +20,7 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       private static final int buildNumber = 535;
+       private static final int buildNumber = 536;

        /** Oldest build of Fred we will talk to */
        private static final int lastGoodBuild = 507;

Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-15 19:16:28 UTC 
(rev 8255)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-15 19:53:25 UTC 
(rev 8256)
@@ -1,6 +1,5 @@
 package freenet.node.fcp;

-import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;

Modified: trunk/freenet/src/freenet/node/fcp/FCPServer.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPServer.java   2006-03-15 19:16:28 UTC 
(rev 8255)
+++ trunk/freenet/src/freenet/node/fcp/FCPServer.java   2006-03-15 19:53:25 UTC 
(rev 8256)
@@ -247,17 +247,17 @@
                        Logger.normal(node, "Starting FCP server on 
"+fcpConfig.getString("bindto")+":"+fcpConfig.getInt("port")+".");
                        fcp = new FCPServer(fcpConfig.getString("bindto"), 
fcpConfig.getInt("port"), node, persistentDownloadsEnabled, 
persistentDownloadsDir, persistentDownloadsInterval);
                        node.setFCPServer(fcp); 
+                       
+                       if(fcp != null) {
+                               cb1.server = fcp;
+                               cb2.server = fcp;
+                               cb3.server = fcp;
+                       }
                }else{
                        Logger.normal(node, "Not starting FCP server as it's 
disabled");
                        fcp = null;
                }
-               
-               if(fcp != null) {
-                       cb1.server = fcp;
-                       cb2.server = fcp;
-                       cb3.server = fcp;
-               }
-               
+       
                fcpConfig.finishedInitialization();
                return fcp;
        }


Reply via email to