Index: /branches/kapa-mods-2007-05/Ohana/src/libkapa/src/KapaOpen.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/libkapa/src/KapaOpen.c	(revision 13345)
+++ /branches/kapa-mods-2007-05/Ohana/src/libkapa/src/KapaOpen.c	(revision 13345)
@@ -0,0 +1,244 @@
+# include "kapa_internal.h"
+
+# define MY_PORT 2500
+# define MY_WAIT 100000
+# define DEBUG 0
+
+static int Nvalid = 0;
+static int *VALID = NULL;
+
+int KapaServerInit (KapaSockAddress *Address) {
+
+  int status, InitSocket, length;
+
+  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:
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  if (DEBUG) fprintf (stderr, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    if (errno == EADDRINUSE) {
+	Address[0].sin_port ++;
+	if (Address[0].sin_port > MY_PORT + 10) exit (2);
+	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 */
+
+  if (DEBUG) fprintf (stderr, "bound to port: %d\n", Address[0].sin_port);
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+  return (InitSocket);
+}
+
+int KapaServerWait (int InitSocket, KapaSockAddress *Address) {
+
+  int i, status, BindSocket;
+  KapaSockAddress Address_in;
+  socklen_t length;
+  u_int32_t addr;
+  fd_set rfds;
+  struct timeval wait;
+
+  Address_in = Address[0];
+
+  length = sizeof(Address_in);
+
+  wait.tv_sec = 0;
+  wait.tv_usec = MY_WAIT;
+
+  /* do I need to clear rfds on each pass? */
+  FD_SET (InitSocket, &rfds);
+  status = select (InitSocket + 1, &rfds, NULL, NULL, &wait);
+  if (status == -1) {
+    perror ("select");
+    abort ();
+  }
+  if (!status) return (-1);
+
+  /* this is a blocking wait; use in a separate thread */
+  // fcntl (InitSocket, F_SETFL, !O_NONBLOCK); 
+
+  if (DEBUG) fprintf (stderr, "init sock: %d, len: %d\n", InitSocket, length);
+  BindSocket = accept (InitSocket, (struct sockaddr *) &Address_in, &length);
+  if (DEBUG) fprintf (stderr, "bind sock: %d\n", BindSocket);
+  if (BindSocket == -1) {
+    perror ("accept: ");
+    exit (2);
+  }
+
+  addr = Address_in.sin_addr.s_addr;
+  if (DEBUG) {
+    fprintf (stderr, "incoming connection from: ");
+    fprintf (stderr, " %u", (0xff & (addr >>  0)));
+    fprintf (stderr, ".%u", (0xff & (addr >>  8)));
+    fprintf (stderr, ".%u", (0xff & (addr >> 16)));
+    fprintf (stderr, ".%u", (0xff & (addr >> 24)));
+    fprintf (stderr, "\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) fprintf (stderr, "connection rejected\n");
+  close (BindSocket);
+  return (-1);
+
+accepted:
+  if (DEBUG) fprintf (stderr, "connection accepted\n");
+  // fcntl (BindSocket, F_SETFL, O_NONBLOCK); 
+  return (BindSocket);
+}
+
+/* load valid ip list */
+int KapaDefineValidIP (char *ipstring) {
+
+  int i, NVALID, ip1, ip2, ip3, ip4, test, status;
+  char string[80];
+
+  if (Nvalid == 0) {
+    Nvalid = 1;
+    ALLOCATE (VALID, int, Nvalid);
+  } else {
+    Nvalid ++;
+    REALLOCATE (VALID, int, Nvalid);
+  }
+
+  status = sscanf (ipstring, "%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) {
+    fprintf (stderr, "invalid IP address %s\n", string);
+    exit (2);
+  }
+  VALID[Nvalid-1] = ip1 | (ip2 << 8) | (ip3 << 16) | (ip4 << 24);
+  return (TRUE);
+}
+
+/* connect to a running server on the specified host */
+int KapaClientSocket (char *hostname) {
+
+  int i, status, InitSocket, length;
+  KapaSockAddress 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) {
+    fprintf (stderr, "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) {
+    fprintf (stderr, "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 (DEBUG) fprintf (stderr, "error connecting: %d\n", errno);
+    if (errno == ECONNREFUSED) {
+      Address.sin_port ++;
+      if (Address.sin_port > MY_PORT + 10) return (-1);
+      goto retry_client;
+    }
+    perror ("connect: ");
+    exit (2);
+  }
+
+  if (DEBUG) fprintf (stderr, "connected on port: %d\n", Address.sin_port);
+  if (DEBUG) fprintf (stderr, "connected\n");
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+  return (InitSocket);
+}
+
+int KapaOpen (char *kapa_exec, char *kapa_name) {
+
+  // kapa_exec may be kapa://host, in which case we attempt to connect to an 
+  // already running kapa, or the program path, in which case we are supposed
+  // to launch it locally, then connect to it.
+
+  int sock, Ntry;
+  char line[128];
+
+  if (!strncmp (kapa_exec, "kapa://", 7)) {
+    sock = KapaClientSocket (&kapa_exec[7]);
+    return (sock);
+  }
+
+  if (kapa_name == NULL) {
+    sprintf (line, "%s &", kapa_exec);
+  } else {
+    sprintf (line, "%s -name %s &", kapa_exec, kapa_name);
+  }
+  system (line);
+
+# define NTRY 500
+  Ntry = 0;
+  while (Ntry < NTRY) {
+    sock = KapaClientSocket ("localhost");
+    if (sock != -1) break;
+    // if (errno != EAGAIN) break;
+    if (errno != ECONNREFUSED) break;
+    usleep (10000);
+    Ntry ++;
+  }
+
+  if (sock < 0) return (-1);
+  return (sock);
+}
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/lib.data/open_kapa.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/lib.data/open_kapa.c	(revision 13345)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/lib.data/open_kapa.c	(revision 13345)
@@ -0,0 +1,226 @@
+# include "display.h"
+# include "shell.h"
+
+/* kapa support for the new version of kapa (v2.0), which has both graph and image
+ * elements merged into a single display device.  The user may now open an arbitrary
+ * number of kapa windows, and the display information is retrieved from kapa across the
+ * socket when it is needed.  Communication is now via an INET socket (not a UNIX socket).
+ */
+
+/* list of available socket connections */
+static int        Active;        // currently active socket (not device)
+static int       *Socket = NULL; // list of available sockets
+static int       *Device = NULL; // list of device numbers for each socked
+static int       Nsocket = 0;    // number of available sockets / devices
+
+void InitKapa () {
+
+  Active  = -1;		      // -1 is the INVALID entry
+  Nsocket = 0;		      // number of defined sockets
+  ALLOCATE (Device, int, 1);
+  ALLOCATE (Socket, int, 1);
+  Device[Active] = 0;  
+  Socket[Active] = 0;  
+}
+
+// returns the number of the requested device, or -1 if not found
+int FindKapaDevice (int thisDevice) {
+
+  int i;
+
+  for (i = 0; i < Nsocket; i++) {
+    if (Device[i] == thisDevice) {
+      return (i);
+    }
+  }
+  return (-1);
+}
+
+// set the active device to the given device number, open if needed
+int open_kapa (int thisDevice) {
+
+  int fd, entry;
+  char *kapa_exec, name[16];
+
+  // find the given device number, or create. set this to active
+  entry = FindKapaDevice (thisDevice);
+  if (entry < 0) {
+    Active = Nsocket;
+    Nsocket ++;
+    REALLOCATE (Device, int, Nsocket);
+    REALLOCATE (Socket, int, Nsocket);
+    Device[Active] = -1;
+    Socket[Active] = -1;
+  } else {
+    Active = entry;
+  }
+
+  // if the (now) active socket is not open, open it
+  if (Socket[Active] < 0) {
+    kapa_exec = get_variable ("KAPA");
+    if (kapa_exec == (char *) NULL) {
+      gprint (GP_ERR, "variable KAPA not found\n");
+      return (FALSE);
+    }
+
+    // KAPA may be either kapa://host or /path/to/program
+
+    snprintf (name, 16, "[%d]", thisDevice);
+    fd = KapaOpen (kapa_exec, name);
+    free (kapa_exec);
+
+    if (fd < 0) {
+      gprint (GP_ERR, "error starting kapa\n");
+      // delete the active entry
+      return (FALSE);
+    } 
+    Device[Active] = thisDevice;
+    Socket[Active] = fd;
+  } 
+  return (TRUE);
+}
+
+/**************** graph ops */
+
+// XXX for now, use a local variable.  later: get from kapa
+static Graphdata graphdata;
+
+void InitGraph () {
+  graphdata.xmin = graphdata.ymin = 0.0;
+  graphdata.xmax = graphdata.ymax = 1.0;
+  graphdata.style = graphdata.ptype = 0;
+  graphdata.ltype = graphdata.color = 0;
+  graphdata.etype = graphdata.ebar = 0;
+  graphdata.lweight = graphdata.size = 1.0;
+    
+  graphdata.coords.pc1_1 = graphdata.coords.pc2_2 = 1.0;
+  graphdata.coords.pc1_2 = graphdata.coords.pc2_1 = 0.0;
+  strcpy (graphdata.coords.ctype, "RA---LIN");
+  graphdata.coords.crval1 = 0.0;
+  graphdata.coords.crval2 = 0.0;
+  graphdata.coords.crpix1 = 0.0;
+  graphdata.coords.crpix2 = 0.0;
+  graphdata.coords.cdelt1 = graphdata.coords.cdelt2 = 1.0;
+  graphdata.flipeast = TRUE;
+  graphdata.flipnorth = FALSE;
+  strcpy (graphdata.axis, "2222");
+  strcpy (graphdata.ticks, "2222");
+  strcpy (graphdata.labels, "2222");
+}
+
+# if (0)
+  /* test Xgraph[0], flush junk from pipe */
+  signal (SIGPIPE, XGraphDead);
+  fcntl (Socket[n], F_SETFL,  O_NONBLOCK); 
+  for (i = 0; (read (Socket[n], buffer, 64) > 0) && (i < 20); i++);
+  fcntl (Socket[n], F_SETFL, !O_NONBLOCK); 
+# endif
+
+/* return pointers for current Xgraph, set if desired, test, open if needed */
+int GetGraph (Graphdata *data, int *fd, int *dev) {
+
+  int thisDevice;
+
+  SetImageDevice (FALSE);
+  if (dev == NULL) {
+    if (Active < 0) {
+      thisDevice = 0;
+    } else {
+      thisDevice = Device[Active];
+    }
+  } else {
+    thisDevice = *dev;
+  }
+  
+  if (!open_kapa (thisDevice)) {
+    return (FALSE);
+  }
+  
+  if (data != NULL) *data = graphdata;
+  if (fd != NULL) *fd = Socket[Active];
+
+  return (TRUE);
+}
+
+/* return pointers for given Xgraph, don't set or open */
+int GetGraphData (Graphdata *data, int *fd, int *dev) {
+
+  int n;
+
+  if (dev == NULL) {
+    if (Active < 0) {
+      gprint (GP_ERR, "invalid Xgraph window %d\n", *dev); 
+      return (FALSE);
+    }
+    *fd = Socket[Active];
+    return (TRUE);
+  } 
+
+  n = FindKapaDevice (*dev);
+  if (n < 0) {
+    gprint (GP_ERR, "invalid Xgraph window %d\n", *dev); 
+    return (FALSE);
+  }
+
+  Active = n;
+
+  if (fd != NULL) *fd = Socket[Active];
+  if (data != NULL) *data = graphdata;
+
+  return (TRUE);
+}
+
+/* assign given values to current Xgraph */
+void SetGraph (Graphdata data) {
+  graphdata = data;
+}
+
+/** internal tracking of current active device type **/
+/* drop this stuff */
+static int       IsImage = FALSE;
+
+int GetCurrentDevice () {
+  return (IsImage);
+}
+
+void SetImageDevice (int state) {
+  IsImage = state;
+}
+
+/************* image ops ***********/
+// XXX for now, use local static:
+
+static char      Ximbuffer[512];
+static double    Xzero;
+static double    Xrange;
+
+void InitImage () {
+  Xzero = 0;
+  Xrange = 1024;
+  strcpy (Ximbuffer, "none");
+}
+
+/* return pointers for current Ximage, set if desired, test, open if needed */
+int GetImage (int *fd, int *N) {
+  int status;
+  status = GetGraph (NULL, fd, N);
+  return (status);
+}
+
+void SetImageName (char *name) {
+  strcpy (Ximbuffer, name);
+}
+
+char *GetImageName () {
+  return (Ximbuffer);
+}
+ 
+// leave this information on kapa, request when needed? 
+void SetImageScale (double zero, double range) {
+  Xzero = zero;
+  Xrange = range;
+}
+void GetImageScale (double *zero, double *range) {
+  *zero = Xzero;
+  *range = Xrange;
+}
