/* ======================================================================= *\
    File   : lyxserver.C, lyxserver.C,v 1.1.1.1 1996/08/19 14:39:32 larsbj Exp
    Author : chb, 2.Nov.1995
    Docu   : To use the lyxserver define the name of the pipe in your
             .lyxrc:
               \serverpipe "/home/myhome/.lyxpipe"
             Then use .lyxpipe.in and .lyxpipe.out to communicate to LyX.
             Each message consists of a single line in ASCII. Input lines
             (client -> LyX) have the following format:
               "LYXCMD:<clientname>:<functionname>:<argument>"
             Answers from LyX look like this:
               "INFO:<clientname>:<functionname>:<data>"
             where <clientname> and <functionname> are just echoed.
             If LyX notifies about a user defined extension key-sequence,
             the line looks like this:
               "NOTIFY:<key-sequence>"
             See the sampleclient.tcl for more information.
    Purpose: implement a client/server lib for LyX
\* ======================================================================= */

#include "config.h"

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "forms.h"

#include "lyxserver.h"
#include "keybind.h"

/* === variables ========================================================= */

lyxcomm lyxpipes;

/* === code ============================================================== */

/* ---F+------------------------------------------------------------------ *\
    Function  : ServerCallback
    Called by : XFORMS
    Purpose   : handle data read from a pipe
    Parameters: fd         - file descriptor
                clientdata - unused
    Returns   : nothing
\* ---F------------------------------------------------------------------- */

void ServerCallback(int fd, void *clientdata)
{
   int res, i;
   char *p, s[100], cmd[100], arg[100], client[100];
   (void)clientdata;

   //* fprintf(stderr, "Server Callback called: (%d)\n", fd);

   // --- read everything -------------------------------------------------

   res = read(fd, s, 99);
   if(res>=0 && res < 100) s[res] = '\0';
   if(res<99)
   {
      int diff = read(fd, s+res, 99-res);
      if(diff>0) res += diff;
      if(res>=0 && res < 100) s[res] = '\0';
   }

   //* fprintf(stderr, "Server Callback called: (%s)\n", s);

   p = s;
   // --- parse the string ------------------------------------------------
   //
   //  Format: LYXCMD:<client>:<func>:<argstring>\n
   //

   while(*p)
   {
      // --- 1. check 'header' ---
      if(0!=strncmp(p, "LYXCMD:", 7))
         return;      // ignore this line
      p += 7;

      // --- 2. for the moment ignore the client name ---
      i = 0;
      while(*p && *p != ':')
         client[i++] = *p++;
      client[i] = '\0';
      if(*p == ':') p++;
      if(!*p) return;

      // --- 3. get function name ---
      i = 0;
      while(*p && *p != ':')
         cmd[i++] = *p++;
      cmd[i] = '\0';

      // --- 4. parse the argument ---
      if(*p == ':') p++;
      if(*p)
      {
         i = 0;
         while(*p && *p != '\n')
            arg[i++] = *p++;
         arg[i] = '\0';
         if(*p) p++;
      }
      else
         arg[0] = '\0';

      // --- lookup and exec the command ----------------------------------

      if(*cmd)
      {
	 int action = LookupLyxFunc(cmd);
	 
	 if (action>=0) {
	    char *rval, buf[256];
	    rval = DispatchFunction((kb_action)action, arg);
	    if(rval && *rval && lyxpipes.outfd > -1)
	    {
	       strcpy(buf, "INFO:");
	       strcat(buf, client);
	       strcat(buf, ":");
	       strcat(buf, cmd);
	       strcat(buf, ":");
	       strcat(buf, rval);
	       strcat(buf, "\n");
	       int len = strlen(buf);
	       write(lyxpipes.outfd, buf, len);
	       // !!! we don't do any error checking -
	       //     if the client won't listen, the message is lost
	       //     and others too maybe; so the client should empty
	       //     the outpipe before issuing a request.
	    }
         }
         // not found
      }
   }  /* while *p */
}


/* ---F+------------------------------------------------------------------ *\
    Function  : LyxNotifyClient
    Called by : WorkAreaKeyPress
    Purpose   : send a notify messge to a client
    Parameters: s - string to send
    Returns   : nothing
\* ---F------------------------------------------------------------------- */

void LyxNotifyClient(char *s)
{
   char buf[100];
   if(lyxpipes.outfd > -1)
   {
      strcpy(buf, "NOTIFY:");
      strcat(buf, s);
      strcat(buf, "\n");
      int len = strlen(buf);
      write(lyxpipes.outfd, buf, len);
   }
}


/* ---F+------------------------------------------------------------------ *\
    Function  : LyxServerInit
    Called by : init
    Purpose   : init the lyxserver mechanism
    Parameters: none
    Returns   : nothing
\* ---F------------------------------------------------------------------- */

void LyxServerInit()
{
   int fd;

   if(!lyxpipes.pipename || !lyxpipes.pipename[0]) return;

   char tmp[1024];

   // --- prepare input pipe ----------------------------------------------

   strcpy(tmp, lyxpipes.pipename);
   strcat(tmp, ".in");
   if(access(tmp, F_OK) == 0)
   {
      fprintf(stderr, "Error: pipe %s already exists\n", tmp);
      return;
   }
   mkfifo(tmp, 0600);
   lyxpipes.infd = fd = open(tmp, O_RDONLY|O_NONBLOCK);
   if(fd<0)
   {
      fprintf(stderr, "Error: could not open pipe %s (%s)\n",
              tmp, "sorry, no strerror");
      return;
   }
   fl_add_io_callback(fd, FL_READ, ServerCallback, 0);

   // --- prepare output pipe ---------------------------------------------

   int l = strlen(tmp);
   tmp[l-2] = 'o'; tmp[l-1] = 'u'; tmp[l] = 't'; tmp[l+1] = '\0';

   if(access(tmp, F_OK) == 0)
   {
      fprintf(stderr, "Error: pipe %s already exists\n", tmp);
      return;
   }
   mkfifo(tmp, 0600);
   if(access(tmp, F_OK) != 0)
   {
      fprintf(stderr, "Error: pipe %s does not exist (%s)\n",
              tmp, "sorry, no strerror");
      return;
   }
   lyxpipes.outfd = fd = open(tmp, O_RDWR);
   if(fd<0)
   {
      fprintf(stderr, "Error: could not open pipe %s (%s)\n",
              tmp, "sorry, no strerror");
      return;
   }
   fcntl(fd, F_SETFL, O_NONBLOCK);
}

/* === End of File: lyxserver.C ========================================== */
