Index: /trunk/Ohana/src/opihi/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/Makefile	(revision 7937)
+++ /trunk/Ohana/src/opihi/Makefile	(revision 7938)
@@ -6,13 +6,12 @@
 ### the include file dependencies need to be cleaned up still
 
-mana:  lib.data lib.shell cmd.basic cmd.data cmd.astro
-dimm:  lib.data lib.shell cmd.basic cmd.data cmd.astro
-dvo:   lib.data lib.shell cmd.basic cmd.data cmd.astro
-pantasks: lib.data lib.shell cmd.basic cmd.data cmd.astro
-pclient:  lib.data lib.shell cmd.basic
-pcontrol: lib.data lib.shell cmd.basic
-
+mana:     	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+dimm:     	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+dvo:      	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+pantasks: 	 lib.data lib.shell cmd.basic cmd.data cmd.astro
 pantasks_server: lib.data lib.shell cmd.basic cmd.data cmd.astro
 pantasks_client: lib.data lib.shell cmd.basic cmd.data cmd.astro
+pclient:  	 lib.data lib.shell cmd.basic
+pcontrol: 	 lib.data lib.shell cmd.basic
 
 LIBS = lib.data lib.shell cmd.basic cmd.data cmd.astro
@@ -24,4 +23,6 @@
 all:
 	for i in $(PROGRAM); do make $$i || exit; done
+	make pantasks_client
+	make pantasks_server
 
 libs:
@@ -33,4 +34,6 @@
 install:
 	for i in $(PROGRAM); do make $$i.install || exit; done
+	make pantasks_client.install
+	make pantasks_server.install
 
 extras-install:
@@ -53,5 +56,8 @@
 	if [ -d pantasks ]; then (cd pantasks && make $@); fi
 
-pantasks_client.install pantasks_server.install:
+pantasks_client.install: pantasks_client
+	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+
+pantasks_server.install: pantasks_server
 	if [ -d pantasks ]; then (cd pantasks && make $@); fi
 
@@ -72,4 +78,3 @@
 	if [ -d "$*" ]; then (cd $* && make uninstall); fi
 
-.PHONY: $(PROGRAM) $(LIBS)
-
+.PHONY: $(PROGRAM) $(LIBS) pantasks_server pantasks_client
Index: /trunk/Ohana/src/opihi/cmd.basic/output.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/output.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/cmd.basic/output.c	(revision 7938)
@@ -5,7 +5,8 @@
 int output (int argc, char **argv) {
   
-  int N;
+  int N, Noutput;
   gpDest dest;
   IOBuffer *buffer;
+  char *output;
 
   dest = GP_LOG;
@@ -21,15 +22,25 @@
   }
     
+  /* set the output target and dump the current buffer there */
   if ((N = get_argument (argc, argv, "-dump"))) {
+    buffer = gprintGetBuffer (dest);
+
+    /* save the current buffer contents */
+    Noutput = buffer[0].Nbuffer;
+    ALLOCATE (output, char, Noutput);
+    memcpy (output, buffer[0].buffer, Noutput);
+    
+    /* set the output target to the specified name */
     remove_argument (N, &argc, argv);
-    buffer = gprintGetBuffer (dest);
-    fprintf (STDERR, "buffer contents: \n");
-    fwrite (buffer[0].buffer, 1, buffer[0].Nbuffer, stderr);
-    fprintf (STDERR, "\n");
+    gprintSetFile (dest, argv[N]);
+    remove_argument (N, &argc, argv);
+
+    /* send the output to the appropriate destination */
+    gwrite (output, 1, Noutput, dest);
     return (TRUE);
   }
     
   if (argc != 2) {
-    gprint (GP_ERR, "USAGE: output <filename>\n");
+    gprint (GP_ERR, "USAGE: output <filename> [-err] [-buffer] [-dump filename]\n");
     return (FALSE);
   }
@@ -46,6 +57,2 @@
   outfile = stdout;
 }
-
-/* we could add the concept of saving the output to a buffer
-   then dumping to the target of the output stream.  not sure
-   what the command should look like... */
Index: /trunk/Ohana/src/opihi/include/shell.h
===================================================================
--- /trunk/Ohana/src/opihi/include/shell.h	(revision 7937)
+++ /trunk/Ohana/src/opihi/include/shell.h	(revision 7938)
@@ -48,7 +48,6 @@
 void          startup               	PROTO((int *argc, char **argv));
 int           multicommand          	PROTO((char *line));
-int           command               	PROTO((char *, char **));
-int           multicommand_client      	PROTO((char *line, int));
-int           command_client           	PROTO((char *, char **));
+void          multicommand_InitServer   PROTO((void));
+int           command               	PROTO((char *line, char **outline, int VERBOSE));
 char         *expand_vars           	PROTO((char *line));
 char         *expand_vectors        	PROTO((char *line));
Index: /trunk/Ohana/src/opihi/lib.data/open_graph.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.data/open_graph.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.data/open_graph.c	(revision 7938)
@@ -1,3 +1,4 @@
 # include "display.h"
+# include "shell.h"
 # define DEBUG 0
 
Index: /trunk/Ohana/src/opihi/lib.data/open_image.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.data/open_image.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.data/open_image.c	(revision 7938)
@@ -1,3 +1,4 @@
 # include "display.h"
+# include "shell.h"
 # define DEBUG 0
 
Index: /trunk/Ohana/src/opihi/lib.shell/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/Makefile	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.shell/Makefile	(revision 7938)
@@ -21,5 +21,4 @@
 $(SDIR)/ListOps.$(ARCH).o	   	\
 $(SDIR)/command.$(ARCH).o               \
-$(SDIR)/command_client.$(ARCH).o        \
 $(SDIR)/CommandOps.$(ARCH).o		\
 $(SDIR)/errors.$(ARCH).o		\
@@ -38,5 +37,4 @@
 $(SDIR)/memstr.$(ARCH).o                \
 $(SDIR)/multicommand.$(ARCH).o          \
-$(SDIR)/multicommand_client.$(ARCH).o   \
 $(SDIR)/parse.$(ARCH).o                 \
 $(SDIR)/parse_commands.$(ARCH).o	\
@@ -45,4 +43,5 @@
 $(SDIR)/timeformat.$(ARCH).o            \
 $(SDIR)/BufferOps.$(ARCH).o             \
+$(SDIR)/SocketOps.$(ARCH).o             \
 $(SDIR)/VectorOps.$(ARCH).o             \
 $(SDIR)/check_stack.$(ARCH).o           \
Index: /trunk/Ohana/src/opihi/lib.shell/SocketOps.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/SocketOps.c	(revision 7938)
+++ /trunk/Ohana/src/opihi/lib.shell/SocketOps.c	(revision 7938)
@@ -0,0 +1,275 @@
+# include "pantasks.h"
+
+# define MY_PORT 2000
+# define MY_WAIT 500
+# define DEBUG 0
+
+static int NVALID;
+static int Nvalid;
+static int *VALID;
+
+int InitServerSocket (SockAddress *Address) {
+
+  int status, InitSocket, length;
+
+# if (0)
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+# endif
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  Address[0].sin_addr.s_addr = INADDR_ANY; // use this line to bind any address / port?
+
+retry_server:
+
+# if (0)  
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+# endif
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    fprintf (stderr, "errno: %d\n", errno);
+    fprintf (stderr, "EACCES: %d\n", EACCES);
+    fprintf (stderr, "EBADF: %d\n", EBADF);
+    fprintf (stderr, "EINVAL: %d\n", EINVAL);
+    fprintf (stderr, "ENOTSOCK: %d\n", ENOTSOCK);
+    fprintf (stderr, "EFAULT: %d\n", EFAULT);
+    fprintf (stderr, "ELOOP: %d\n", ELOOP);
+    fprintf (stderr, "ENAMETOOLONG: %d\n", ENAMETOOLONG);
+    fprintf (stderr, "ENOENT: %d\n", ENOENT);
+    fprintf (stderr, "ENOMEM: %d\n", ENOMEM);
+    fprintf (stderr, "ENOTDIR: %d\n", ENOTDIR);
+    fprintf (stderr, "EROFS: %d\n", EROFS);
+
+    Address[0].sin_port ++;
+    if (Address[0].sin_port > MY_PORT + 10) exit (2);
+    fprintf (stderr, "trying next port: %d\n", Address[0].sin_port);
+    goto retry_server;
+
+    perror ("bind: ");
+    exit (2);
+  }
+  /* repeated starts of the server are limited by xinetd or something:
+     requires 60sec timeout of the selected socket */
+
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+  return (InitSocket);
+}
+
+int WaitServerSocket (int InitSocket, SockAddress *Address) {
+
+  int i, BindSocket, length;
+  SockAddress Address_in;
+  u_int32_t addr;
+
+  Address_in = Address[0];
+
+  length = sizeof(Address_in);
+
+  /* this is a blocking wait; use in a separate thread */
+  fcntl (InitSocket, F_SETFL, !O_NONBLOCK); 
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  BindSocket = accept (InitSocket, (struct sockaddr *) &Address_in, &length);
+  if (DEBUG) gprint (GP_ERR, "bind sock: %d\n", BindSocket);
+  if (BindSocket == -1) {
+    perror ("accept: ");
+    exit (2);
+  }
+
+  addr = Address_in.sin_addr.s_addr;
+  if (DEBUG) {
+    gprint (GP_ERR, "incoming connection from: ");
+    gprint (GP_ERR, " %u", (0xff & (addr >>  0)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >>  8)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >> 16)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >> 24)));
+    gprint (GP_ERR, "\n");
+  }
+
+  if (Nvalid == 0) goto accepted;
+
+  for (i = 0; i < Nvalid; i++) {
+    /* valid IP addresses may be machines (120.90.121.142) or 
+       class C networks (120.90.121.0) */
+       
+    /* for machine, address must match */
+    if ((0xff & (VALID[i] >> 24)) != 0) {
+      if (addr == VALID[i]) goto accepted;
+    }
+
+    /* for network, lower three bytes of address must match */
+    if ((0xff & (VALID[i] >> 24)) == 0) {
+      if ((0x00ffffff & addr) == VALID[i]) goto accepted;
+    }
+  }
+
+  if (DEBUG) gprint (GP_ERR, "connection rejected\n");
+  close (BindSocket);
+  return (-1);
+
+accepted:
+  if (DEBUG) gprint (GP_ERR, "connection accepted\n");
+  fcntl (BindSocket, F_SETFL, O_NONBLOCK); 
+  return (BindSocket);
+}
+
+int GetClientSocket (char *hostname) {
+
+  int i, status, InitSocket, length;
+  SockAddress Address;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+
+  if (DEBUG) {
+    gprint (GP_ERR, "trying %s (%s:%d)...", host[0].h_name, hostip, MY_PORT);
+  }
+
+  Address.sin_family = AF_INET;
+  Address.sin_port   = MY_PORT;
+
+retry_client:
+  status = inet_aton (hostip, &Address.sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  status = connect (InitSocket, (struct sockaddr *) &Address, length);
+  if (status == -1) {
+    if (errno == ECONNREFUSED) {
+      Address.sin_port ++;
+      if (Address.sin_port > MY_PORT + 10) exit (2);
+      fprintf (stderr, "trying next port: %d\n", Address.sin_port);
+      goto retry_client;
+    }
+    perror ("connect: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "connected\n");
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+  return (InitSocket);
+}
+
+int InitServerSocket_Named (char *hostname, SockAddress *Address) {
+
+  int i, status, InitSocket, length;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    perror ("bind: ");
+    exit (2);
+  }
+
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "socket listening on %s (%s:%d)\n", host[0].h_name, hostip, MY_PORT);
+  return (InitSocket);
+}
+
+/* load valid ip list */
+int DefineValidIP () {
+
+  int i, Nvalid, ip1, ip2, ip3, ip4, test, status;
+  char string[80];
+
+  Nvalid = 0;
+  NVALID = 10;
+  ALLOCATE (VALID, int, NVALID);
+  for (i = 0; VarConfigEntry ("VALID_IP", "%s", i, string) != NULL; i++) {
+    status = sscanf (string, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
+    test = TRUE;
+    test &= (status == 4);
+    test &= ((ip1 > 0) && (ip1 < 256)); 
+    test &= ((ip2 > 0) && (ip2 < 256)); 
+    test &= ((ip3 > 0) && (ip3 < 256)); 
+    test &= ((ip4 >=0) && (ip4 < 256)); 
+    if (!test) {
+      gprint (GP_ERR, "invalid IP address %s\n", string);
+      exit (2);
+    }
+    VALID[Nvalid] = ip1 | (ip2 << 8) | (ip3 << 16) | (ip4 << 24);
+    Nvalid ++;
+    CHECK_REALLOCATE (VALID, int, NVALID, Nvalid, 10);
+  }
+  NVALID = Nvalid;
+  REALLOCATE (VALID, int, NVALID);
+  if (NVALID == 0) {
+    free (VALID);
+    VALID = NULL;
+  }
+}
Index: /trunk/Ohana/src/opihi/lib.shell/command.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/command.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.shell/command.c	(revision 7938)
@@ -1,6 +1,6 @@
 # include "opihi.h"
-# define VERBOSE 0
+# define DEBUG 0
 
-int command (char *line, char **outline) {
+int command (char *line, char **outline, int VERBOSE) {
 
   int i, status, argc;
@@ -26,4 +26,8 @@
   *outline = line;
   
+  # if (DEBUG) 
+  fprintf (stderr, "line: %s\n", line);
+  # endif
+
   argv = parse_commands (line, &argc);
   if (argc == 0) return (TRUE);  /* empty command or assignment */
@@ -33,7 +37,7 @@
   for (i = 0; i < argc; i++) targv[i] = argv[i];
 
-  cmd = MatchCommand (argv[0], TRUE, FALSE);
+  cmd = MatchCommand (argv[0], VERBOSE, FALSE);
   if (cmd == NULL) {
-    status = FALSE;
+    status = -1;
   } else {
     free (argv[0]);
@@ -53,5 +57,16 @@
 
   set_int_variable ("STATUS", status);
-  if (VERBOSE) gprint (GP_ERR, "command: %s, status: %d\n", line, status);
+
+  # if (DEBUG) 
+  gprint (GP_ERR, "command: %s, status: %d\n", line, status);
+  # endif
+
   return (status);
 }
+
+/* parse the input line, search for the corresponding command, and execute it
+   if no match is found, return -1; this is used above to distinguish between
+   a command error and an unknown command.  if VERBOSE is true, unknown commands
+   result in an error message.  The input line is freed and the resulting parsed
+   line is returned on 'outline'
+*/
Index: unk/Ohana/src/opihi/lib.shell/command_client.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/command_client.c	(revision 7937)
+++ 	(revision )
@@ -1,62 +1,0 @@
-# include "opihi.h"
-# define VERBOSE 0
-
-// this function is identical to the normal command.c function,
-// but it returns -1 for a missing command and does not echo the
-// 'missing command' error message
-
-int command_client (char *line, char **outline) {
-
-  int i, status, argc;
-  char **argv, **targv;
-  Command *cmd;
-
-  /* force a space between ! and first word: !ls becomes ! ls */
-  if (line[0] == '!') {
-    REALLOCATE (line, char, strlen(line) + 5);
-    memmove (&line[2], &line[1], strlen(&line[1]) + 1);
-    line[1] = ' ';
-  }
-
-  /* expand anything of the form $fred or $fred$sam, etc */ 
-  line = expand_vars (line);     /* line is freed here, new one allocated */
-  /* expand anything of the form fred[N] */ 
-  line = expand_vectors (line);  /* line is freed here, new one allocated */
-  /* solve math expresions, assign variable, if needed */
-  line = parse (line);        /* line is freed here, new one allocated */
-  /* any entry in line of the form {foo} returns value or tmp vector / buffer */
-
-  /* we may have reallocated line, return new pointer */
-  *outline = line;
-  
-  argv = parse_commands (line, &argc);
-  if (argc == 0) return (TRUE);  /* empty command or assignment */
-
-  /* save the original values of argv since command may modify the array */
-  ALLOCATE (targv, char *, argc);
-  for (i = 0; i < argc; i++) targv[i] = argv[i];
-
-  // use non-verbose mode to skip 'missing command' error message
-  cmd = MatchCommand (argv[0], FALSE, FALSE);
-  if (cmd == NULL) {
-    status = -1;
-  } else {
-    free (argv[0]);
-    argv[0] = strcreate (cmd[0].name);
-    targv[0] = argv[0];
-    status = (*cmd[0].func) (argc, argv);
-  }
-  for (i = 0; i < argc; i++) free (targv[i]);
-  free (targv);
-  free (argv);
-
-  if (!status) {
-    char *msg;
-    msg = get_variable_ptr ("ERRORMSG");
-    if (msg != (char *) NULL) gprint (GP_ERR, "%s\n", msg);
-  }
-
-  set_int_variable ("STATUS", status);
-  if (VERBOSE) gprint (GP_ERR, "command: %s, status: %d\n", line, status);
-  return (status);
-}
Index: /trunk/Ohana/src/opihi/lib.shell/exec_loop.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 7938)
@@ -30,5 +30,7 @@
     lists[ThisList].n = n; 
     line = lists[ThisList].line[n];
+
     status = multicommand (line);
+
     if (line != NULL) free (line);
     n = lists[ThisList].n;
Index: /trunk/Ohana/src/opihi/lib.shell/multicommand.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/multicommand.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.shell/multicommand.c	(revision 7938)
@@ -1,3 +1,31 @@
 # include "opihi.h"
+
+static int server = 0;
+
+void multicommand_InitServer () {
+
+  char hostname[256], PASSWORD[256];
+
+  if (server != 0) {
+    /* check if down? */
+    fprintf (stderr, "error: server fd already defined\n");
+    exit (1);
+  }
+
+  /* find the defined server hostname */
+  if (VarConfig ("PANTASKS_SERVER", "%s", hostname) == NULL) {
+    gprint (GP_ERR, "pantasks server host undefined\n");
+    exit (2);
+  }
+
+  /* attempt to connect to the server */
+  server = GetClientSocket (hostname);
+
+  /* here we can perform the security handshaking */
+  VarConfig ("PASSWORD", "%s", PASSWORD);
+  SendCommand (server, strlen(PASSWORD), PASSWORD);
+  
+  return;
+}
 
 /* take input line and split into multiple lines
@@ -6,6 +34,10 @@
 int multicommand (char *line) {
  
-  int done, status;
+  int done, status, verbose;
   char *p, *q, *tmpline, *outline;
+  IOBuffer message;
+
+  /* if no server is defined, use 'verbose' mode for 'command' */ 
+  verbose = (server == 0);
 
   p = line; 
@@ -21,5 +53,54 @@
     stripwhite (tmpline);
     if (*tmpline) {
-      status = command (tmpline, &outline);
+
+      status = command (tmpline, &outline, verbose);
+
+      if (status == -1) {
+	if (server) {
+	  // send the command to the server instead
+	  if (!SendMessage (server, outline)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  }
+
+	  // receive the resulting stderr
+	  if (ExpectMessage (server, 2.0, &message)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  } else {
+	    gwrite (message.buffer, 1, message.Nbuffer, GP_ERR);
+	  }
+
+	  // receive the resulting stdout
+	  if (ExpectMessage (server, 2.0, &message)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  } else {
+	    gwrite (message.buffer, 1, message.Nbuffer, GP_LOG);
+	  }
+	} else {
+	  // if no server is defined, we treat an unknown command as an error
+	  status = FALSE;
+	}	
+      }
+
       if (outline != NULL) free (outline);
       if (!status && auto_break) done = TRUE;
@@ -31,2 +112,9 @@
 
 /* should skip ; surrounded by "" */
+
+/* commands which are not found are sent to the server socket if 
+   defined. commands executed by the server return their stderr
+   and stdout streams.  server commands should probably not block
+   the server for very long or multiple clients will interfere
+   with each other.  
+*/
Index: unk/Ohana/src/opihi/lib.shell/multicommand_client.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/multicommand_client.c	(revision 7937)
+++ 	(revision )
@@ -1,48 +1,0 @@
-# include "opihi.h"
-
-/* take input line and split into multiple lines
-   at the semi-colons.  send these to 'command' */
-
-/* this function should check for a return value of
-   -1 which means invalid command */
-
-int multicommand_client (char *line, int server) {
- 
-  int done, status;
-  char *p, *q, *tmpline, *outline;
-  IOBuffer message;
-
-  p = line; 
-  done = FALSE;
-  status = TRUE;
-  while (!done) {
-    q = strchr (p, ';');
-    if (q == NULL) {
-      q = p + strlen(p);
-      done = TRUE;
-    }
-    tmpline = strncreate (p, q - p);
-    stripwhite (tmpline);
-    if (*tmpline) {
-      status = command_client (tmpline, &outline);
-      if (status == -1) {
-	// send the command to the server instead
-	SendMessage (server, outline);
-
-	// receive the resulting stderr
-	status = ExpectMessage (server, 2.0, &message);
-	fwrite (message.buffer, 1, message.Nbuffer, stderr);
-
-	// receive the resulting stdout
-	status = ExpectMessage (server, 2.0, &message);
-	fwrite (message.buffer, 1, message.Nbuffer, stderr);
-      }
-      if (outline != NULL) free (outline);
-      if (!status && auto_break) done = TRUE;
-    }
-    p = q + 1;
-  }
-  return (status);
-}
-
-/* should skip ; surrounded by "" */
Index: /trunk/Ohana/src/opihi/lib.shell/startup.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/startup.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/lib.shell/startup.c	(revision 7938)
@@ -121,5 +121,5 @@
       rcfile = get_variable ("RCFILE");
       sprintf (line, "input %s/%s", home, rcfile);
-      status = command (line, &outline);
+      status = command (line, &outline, TRUE);
       if (outline != (char *) NULL) free (outline);
     }
@@ -144,5 +144,5 @@
       ALLOCATE (line, char, 1024);
       sprintf (line, "input %s", list[i]);
-      status = command (line, &outline);
+      status = command (line, &outline, TRUE);
       if (outline != (char *) NULL) free (outline);
     }
Index: /trunk/Ohana/src/opihi/pantasks/ListenClients.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/ListenClients.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/pantasks/ListenClients.c	(revision 7938)
@@ -6,6 +6,4 @@
 static int *clients;
 static IOBuffer *buffers;
-
-/* outline of functions we need here */
 
 void InitClients () {
@@ -17,11 +15,6 @@
 }
 
+/* add this client to the client table, create an IOBuffer for it */
 void AddNewClient (int client) {
-
-  /* add this client to the client table */
-  /* need to create an IOBuffer for each possible client?
-     we may not read a complete line in one pass.  have to 
-     wait until we get the complete lines...
-  */
 
   if (DEBUG) gprint (GP_LOG, "adding a new client (%d)\n", client);
@@ -36,4 +29,5 @@
 }
 
+/* select for messages from the current clients; wait for 0.5s before updating client list */
 void *ListenClients (void *data) {
   
@@ -48,23 +42,10 @@
   gprintInit ();  // each thread needs to init the printing system
 
-  while (0) {
-
-    Ncurrent = Nclients;
-    for (i = 0; i < Ncurrent; i++) {
-      ExpectMessage (clients[i], 0.25, &buffers[i]);
-      if (DEBUG) gprint (GP_ERR, "read %d from client %d\n", buffers[i].Nbuffer, i);
-      if (buffers[i].Nbuffer) {
-	if (DEBUG) gprint (GP_ERR, "%s\n", buffers[i].buffer);
-      }
-    }
-    usleep (250000);
-  }
-
   while (1) {
 
     /* Wait up to 0.5 second - need to timeout to update client list */
     /* timeout gets mucked: need to reset before each select */
-    timeout.tv_sec = 1;
-    timeout.tv_usec = 000000;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 500000;
 
     /* place all of the clients in the fdSet */
Index: /trunk/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 7937)
+++ /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 7938)
@@ -70,12 +70,10 @@
 $(SDIR)/client_shell.$(ARCH).o \
 $(SDIR)/invalid.$(ARCH).o \
-$(SDIR)/init_client.$(ARCH).o \
-$(SDIR)/SocketOps.$(ARCH).o
+$(SDIR)/init_client.$(ARCH).o
 
 server = \
 $(SDIR)/pantasks_server.$(ARCH).o \
 $(SDIR)/ListenClients.$(ARCH).o \
-$(SDIR)/CheckPassword.$(ARCH).o \
-$(SDIR)/SocketOps.$(ARCH).o
+$(SDIR)/CheckPassword.$(ARCH).o
 
 libs = \
Index: unk/Ohana/src/opihi/pantasks/SocketOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/SocketOps.c	(revision 7937)
+++ 	(revision )
@@ -1,275 +1,0 @@
-# include "pantasks.h"
-
-# define MY_PORT 2000
-# define MY_WAIT 500
-# define DEBUG 0
-
-static int NVALID;
-static int Nvalid;
-static int *VALID;
-
-int InitServerSocket (SockAddress *Address) {
-
-  int status, InitSocket, length;
-
-# if (0)
-  struct hostent  *host;
-  char tmpline[80], hostip[80];
-
-  host = gethostbyname (hostname);
-  bzero (hostip, 80);
-  for (i = 0; i < host[0].h_length; i++) {
-    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
-    strcat (hostip, tmpline);
-    if (i < host[0].h_length - 1) strcat (hostip, ".");
-  }
-# endif
-  
-  Address[0].sin_family = AF_INET;
-  Address[0].sin_port   = MY_PORT;
-  Address[0].sin_addr.s_addr = INADDR_ANY; // use this line to bind any address / port?
-
-retry_server:
-
-# if (0)  
-  status = inet_aton (hostip, &Address[0].sin_addr);
-  if (!status) {
-    gprint (GP_ERR, "invalid address\n");
-    exit (2);
-  }
-# endif
-
-  length = sizeof(Address[0]);
-
-  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
-  if (InitSocket == -1) {
-    perror ("socket: ");
-    exit (2);
-  }
-
-  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
-  status = bind (InitSocket, (struct sockaddr *) Address, length);
-  if (status == -1) {
-    fprintf (stderr, "errno: %d\n", errno);
-    fprintf (stderr, "EACCES: %d\n", EACCES);
-    fprintf (stderr, "EBADF: %d\n", EBADF);
-    fprintf (stderr, "EINVAL: %d\n", EINVAL);
-    fprintf (stderr, "ENOTSOCK: %d\n", ENOTSOCK);
-    fprintf (stderr, "EFAULT: %d\n", EFAULT);
-    fprintf (stderr, "ELOOP: %d\n", ELOOP);
-    fprintf (stderr, "ENAMETOOLONG: %d\n", ENAMETOOLONG);
-    fprintf (stderr, "ENOENT: %d\n", ENOENT);
-    fprintf (stderr, "ENOMEM: %d\n", ENOMEM);
-    fprintf (stderr, "ENOTDIR: %d\n", ENOTDIR);
-    fprintf (stderr, "EROFS: %d\n", EROFS);
-
-    Address[0].sin_port ++;
-    if (Address[0].sin_port > MY_PORT + 10) exit (2);
-    fprintf (stderr, "trying next port: %d\n", Address[0].sin_port);
-    goto retry_server;
-
-    perror ("bind: ");
-    exit (2);
-  }
-  /* repeated starts of the server are limited by xinetd or something:
-     requires 60sec timeout of the selected socket */
-
-  status = listen (InitSocket, 10);
-  if (status == -1) {
-    perror ("listen: ");
-    exit (2);
-  }
-  return (InitSocket);
-}
-
-int WaitServerSocket (int InitSocket, SockAddress *Address) {
-
-  int i, BindSocket, length;
-  SockAddress Address_in;
-  u_int32_t addr;
-
-  Address_in = Address[0];
-
-  length = sizeof(Address_in);
-
-  /* this is a blocking wait; use in a separate thread */
-  fcntl (InitSocket, F_SETFL, !O_NONBLOCK); 
-
-  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
-  BindSocket = accept (InitSocket, (struct sockaddr *) &Address_in, &length);
-  if (DEBUG) gprint (GP_ERR, "bind sock: %d\n", BindSocket);
-  if (BindSocket == -1) {
-    perror ("accept: ");
-    exit (2);
-  }
-
-  addr = Address_in.sin_addr.s_addr;
-  if (DEBUG) {
-    gprint (GP_ERR, "incoming connection from: ");
-    gprint (GP_ERR, " %u", (0xff & (addr >>  0)));
-    gprint (GP_ERR, ".%u", (0xff & (addr >>  8)));
-    gprint (GP_ERR, ".%u", (0xff & (addr >> 16)));
-    gprint (GP_ERR, ".%u", (0xff & (addr >> 24)));
-    gprint (GP_ERR, "\n");
-  }
-
-  if (Nvalid == 0) goto accepted;
-
-  for (i = 0; i < Nvalid; i++) {
-    /* valid IP addresses may be machines (120.90.121.142) or 
-       class C networks (120.90.121.0) */
-       
-    /* for machine, address must match */
-    if ((0xff & (VALID[i] >> 24)) != 0) {
-      if (addr == VALID[i]) goto accepted;
-    }
-
-    /* for network, lower three bytes of address must match */
-    if ((0xff & (VALID[i] >> 24)) == 0) {
-      if ((0x00ffffff & addr) == VALID[i]) goto accepted;
-    }
-  }
-
-  if (DEBUG) gprint (GP_ERR, "connection rejected\n");
-  close (BindSocket);
-  return (-1);
-
-accepted:
-  if (DEBUG) gprint (GP_ERR, "connection accepted\n");
-  fcntl (BindSocket, F_SETFL, O_NONBLOCK); 
-  return (BindSocket);
-}
-
-int GetClientSocket (char *hostname) {
-
-  int i, status, InitSocket, length;
-  SockAddress Address;
-  struct hostent  *host;
-  char tmpline[80], hostip[80];
-
-  host = gethostbyname (hostname);
-  bzero (hostip, 80);
-  for (i = 0; i < host[0].h_length; i++) {
-    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
-    strcat (hostip, tmpline);
-    if (i < host[0].h_length - 1) strcat (hostip, ".");
-  }
-
-  if (DEBUG) {
-    gprint (GP_ERR, "trying %s (%s:%d)...", host[0].h_name, hostip, MY_PORT);
-  }
-
-  Address.sin_family = AF_INET;
-  Address.sin_port   = MY_PORT;
-
-retry_client:
-  status = inet_aton (hostip, &Address.sin_addr);
-  if (!status) {
-    gprint (GP_ERR, "invalid address\n");
-    exit (2);
-  }
-
-  length = sizeof(Address);
-
-  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
-  if (InitSocket == -1) {
-    perror ("socket: ");
-    exit (2);
-  }
-
-  status = connect (InitSocket, (struct sockaddr *) &Address, length);
-  if (status == -1) {
-    if (errno == ECONNREFUSED) {
-      Address.sin_port ++;
-      if (Address.sin_port > MY_PORT + 10) exit (2);
-      fprintf (stderr, "trying next port: %d\n", Address.sin_port);
-      goto retry_client;
-    }
-    perror ("connect: ");
-    exit (2);
-  }
-
-  if (DEBUG) gprint (GP_ERR, "connected\n");
-  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
-  return (InitSocket);
-}
-
-int InitServerSocket_Named (char *hostname, SockAddress *Address) {
-
-  int i, status, InitSocket, length;
-  struct hostent  *host;
-  char tmpline[80], hostip[80];
-
-  host = gethostbyname (hostname);
-  bzero (hostip, 80);
-  for (i = 0; i < host[0].h_length; i++) {
-    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
-    strcat (hostip, tmpline);
-    if (i < host[0].h_length - 1) strcat (hostip, ".");
-  }
-  
-  Address[0].sin_family = AF_INET;
-  Address[0].sin_port   = MY_PORT;
-  status = inet_aton (hostip, &Address[0].sin_addr);
-  if (!status) {
-    gprint (GP_ERR, "invalid address\n");
-    exit (2);
-  }
-
-  length = sizeof(Address[0]);
-
-  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
-  if (InitSocket == -1) {
-    perror ("socket: ");
-    exit (2);
-  }
-
-  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
-  status = bind (InitSocket, (struct sockaddr *) Address, length);
-  if (status == -1) {
-    perror ("bind: ");
-    exit (2);
-  }
-
-  status = listen (InitSocket, 10);
-  if (status == -1) {
-    perror ("listen: ");
-    exit (2);
-  }
-
-  if (DEBUG) gprint (GP_ERR, "socket listening on %s (%s:%d)\n", host[0].h_name, hostip, MY_PORT);
-  return (InitSocket);
-}
-
-/* load valid ip list */
-int DefineValidIP () {
-
-  int i, Nvalid, ip1, ip2, ip3, ip4, test, status;
-  char string[80];
-
-  Nvalid = 0;
-  NVALID = 10;
-  ALLOCATE (VALID, int, NVALID);
-  for (i = 0; VarConfigEntry ("VALID_IP", "%s", i, string) != NULL; i++) {
-    status = sscanf (string, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
-    test = TRUE;
-    test &= (status == 4);
-    test &= ((ip1 > 0) && (ip1 < 256)); 
-    test &= ((ip2 > 0) && (ip2 < 256)); 
-    test &= ((ip3 > 0) && (ip3 < 256)); 
-    test &= ((ip4 >=0) && (ip4 < 256)); 
-    if (!test) {
-      gprint (GP_ERR, "invalid IP address %s\n", string);
-      exit (2);
-    }
-    VALID[Nvalid] = ip1 | (ip2 << 8) | (ip3 << 16) | (ip4 << 24);
-    Nvalid ++;
-    CHECK_REALLOCATE (VALID, int, NVALID, Nvalid, 10);
-  }
-  NVALID = Nvalid;
-  REALLOCATE (VALID, int, NVALID);
-  if (NVALID == 0) {
-    free (VALID);
-    VALID = NULL;
-  }
-}
Index: /trunk/Ohana/src/opihi/pantasks/client_shell.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/client_shell.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/pantasks/client_shell.c	(revision 7938)
@@ -5,8 +5,6 @@
 
   int i, Nbad, status, server;
-  char *line, *outline, *prompt, *history;
-  char hostname[256], PASSWORD[256];
+  char *line, *prompt, *history;
   pid_t ppid;
-  IOBuffer message;
 
   general_init (&argc, argv);
@@ -17,15 +15,7 @@
   welcome ();
 
-  /* connect to the server */
-  if (VarConfig ("PANTASKS_SERVER", "%s", hostname) == NULL) {
-    gprint (GP_ERR, "pantasks server host undefined\n");
-    exit (2);
-  }
-  server = GetClientSocket (hostname);
+  /* attempt to connect to the pantasks server (exit on failure) */
+  multicommand_InitServer ();
 
-  /* here we can perform the security handshaking */
-  VarConfig ("PASSWORD", "%s", PASSWORD);
-  SendCommand (server, strlen(PASSWORD), PASSWORD);
-  
   Nbad = 0;
   while (1) {  /** must exit with command "exit" or "quit" */
@@ -50,46 +40,13 @@
 
     stripwhite (line);
-    
-    /* check for commands to be caught by client */
-    /* use the standard command parser? */
-    /* XXX the exit status of command does not allow us
-       to distinguish 'failed command' and 'command not found' */
-    /* XXX eventually replace this with a multicommand parsing */
-    status = multicommand_client (line, server);
-    add_history (line);
-    append_history (1, history);
 
+    if (*line) {
+	status = multicommand (line);
+	add_history (line);
+	append_history (1, history);
+    }
     free (line);
   }
 }
-
-# if 0
-    /* command was not caught by client, send to server */
-    if (*outline && !status ) {
-      gprint (GP_ERR, "sending message to %d: %s\n", server, outline);
-      SendMessage (server, outline);
-      add_history (outline);
-      append_history (1, history);
-
-      // XXX add this in and print to stdout
-      status = ExpectMessage (server, 2.0, &message);
-      // fprintf (stderr, "got stdout message: %d bytes\n", message.Nbuffer);
-      fwrite (message.buffer, 1, message.Nbuffer, stderr);
-      // fprintf (stderr, "end message\n");
-
-      // fprintf (stderr, "got message: %d bytes\n", message.Nbuffer);
-      // for (i = 0; i < message.Nbuffer; i++) {
-      // fprintf (stderr, "%d %d %c\n", i, message.buffer[i], message.buffer[i]);
-      // }
-      // fwrite (message.buffer, 1, message.Nbuffer, stderr);
-      // fprintf (stderr, "end message\n");
-
-      // XXX add this in and print to stdout
-      status = ExpectMessage (server, 2.0, &message);
-      // fprintf (stderr, "got stderr message: %d bytes\n", message.Nbuffer);
-      fwrite (message.buffer, 1, message.Nbuffer, stderr);
-      // fprintf (stderr, "end message\n");
-    }
-# endif
 
 /* 
Index: /trunk/Ohana/src/opihi/pantasks/pantasks_client.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/pantasks_client.c	(revision 7937)
+++ /trunk/Ohana/src/opihi/pantasks/pantasks_client.c	(revision 7938)
@@ -10,7 +10,10 @@
 void program_init (int *argc, char **argv) {
   
+  auto_break = TRUE;
+
   /* load the commands used by this implementation */
   InitBasic ();
   InitData ();
+  InitAstro ();
   InitPantasksClient ();
 
@@ -19,6 +22,4 @@
   rl_readline_name = opihi_name;
   rl_attempted_completion_function = command_completer;
-  rl_event_hook = NULL;
-  rl_set_keyboard_input_timeout (100000); 
 
   set_str_variable ("HISTORY", opihi_history);
@@ -26,6 +27,4 @@
   set_str_variable ("RCFILE", opihi_rcfile);
 
-  /* should we trap some commands and exec them locally? */
-  /* help would be an obvious example... */
 # ifdef HELPDIR_DEFAULT
   set_str_variable ("HELPDIR", MACRO_NAME(HELPDIR_DEFAULT));
@@ -45,10 +44,7 @@
 
 /* add program-dependent exit functions here */
-/* unclear what we should do with the plotting functions:
-   do we keep the data only on the server, with all plotting 
-   taking place on the server? or what? */
 void cleanup () {
-  // QuitImage ();
-  // QuitGraph ();
+  QuitImage ();
+  QuitGraph ();
   return;
 }
@@ -60,5 +56,6 @@
 }
 
-/* call to opihi shell */
+/* call to client_shell: this opihi tool uses a slightly different
+   shell function from the standard tools */
 int main (int argc, char **argv) {
   int status;
