/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++   MIDAS monitor routines PREPB  +++++++++++++++++++++++++
.LANGUAGE    C

.IDENTIFICATION  Module prepb.c

.AUTHOR  K. Banse 		ESO - Garching

.KEYWORDS
  MIDAS monitor

.COMMENTS
  holds  inmail, busymail, trigback, showback, waitback, setback

.ENVIRONMENT  VMS and UNIX

.VERSION  [1.00] 930125:  pulled out from prepj.c

 090504		last modif
------------------------------------------------------------------------*/
 
#include <stdlib.h>
#include <signal.h>

#ifndef SIGUSR1
#define SIGUSR1 30
#endif

#ifndef SIGUSR2
#define SIGUSR2 31
#endif

#include <fileexts.h>
#include <osyparms.h>
#include <monitdef.h>
#include <xconndef.h>
#include <midback.h>

#define TIMS 2			/* no. of seconds to wait in file comm. */

static char   mail_in[2];

static int    YesSignal,  outpid;
static int    bkstat[MAX_BACK] = {0,0,0,0,0,0,0,0,0,0};	  /* MAX_BACK = 10 */ 



static void intdum1()
{

YesSignal = 1;

}

/*

*/
 
int inmail(flag,cpntr,ipntr)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  read 2 lines from file "FORGRxy.SBOX" + store into command line
  where xy is my own DAZUNIT
.ALGORITHM
 a) If file_in flag not set, poll for existence of file "FORGRxy.SBOX"
    in current directory.
    If found, read line with Midas command (preceded by 2-digit
    sender Midas unit) and try to read 2. line (NOT required) with PID
    of sender, then raise file_in flag if NOT from interrupt;

 b) If file_in flag is set, we get here after command is done and prepare
    the response:
    delete first the SBOX file, then create an RBOX
    file which also contains the sender Midas unit in the file name and fill
    it with return info (this indicates to the Midas sender, that the command
    has been executed), lower file_in flag and go again into polling loop
 
 flag = 1 - get next input (send status back first)
 flag = 8 - send status back only
 flag = 9 - close connection 
 flag = 10 - send data back for XCKRDx calls
 flag = 11 - get data for XCKWRx calls

.RETURNS
 success code
-----------------------------------------------------------------*/

int   flag;
char  *cpntr;
int   *ipntr;

{
int   fp, nn, reto;
int   kk, stat;
static int file_in = 0;

unsigned int time;

char  cptr[80];



if (server.MODE == 1)			/* osx services */
   {
   if (flag == 10) 			/* send back info for XCKRDx calls */
      {
      file_in = 0;
      kk = *ipntr++;			/* that's the type */
      nn = ServKWrite(kk,cpntr,ipntr,&reto);	/* send key-values */
      if (nn != 0) 
         return(reto);
      else
         return (0);
      }
   else if (flag == 11)
      {
      kk = *ipntr++;                    /* that's the type */
      nn = ServKRead(kk,cpntr,ipntr,&reto);     /* get key-values */
      if (nn != 0)
         return(reto);
      else
         return (0);
      }

   else if (flag == 9)
      {
      if (file_in == 1)
         {                              /* try to send last status */
         file_in = 0;                   /* but ignore return from ServWrite */
         (void) ServWrite(KIWORDS[OFF_PRSTAT],&reto);
         }
      nn = ServClose(&reto);
      if (nn != 0)
         return(reto);
      else
         return (0);
      }


   if (file_in == 1)
      {
      file_in = 0;
      if (flag == 9)
         nn = ServWrite(99,&reto);
      else
         nn = ServWrite(KIWORDS[OFF_PRSTAT],&reto);
      if (nn != 0) return(reto);
      }

   if (flag == 1)
      {
      nn = ServRead(LINE.STR,MAX_LINE,&server.FUNC,&reto);
      if (nn  < 0)
         return(reto);
      else
         goto show_cmnd;
      }
   return (0);					/* also code for flag = 8 */
   }


XCONNECT.SBOX[XCONNECT.OFFS] = FRONT.DAZUNIT[0];      /* put own Midas unit */
XCONNECT.SBOX[XCONNECT.OFFS+1] = FRONT.DAZUNIT[1];

if (file_in == 1)
   {
   file_in = 0;
   XCONNECT.RBOX[XCONNECT.OFFS] = FRONT.DAZUNIT[0];	/* own Midas unit  */
   XCONNECT.RBOX[XCONNECT.OFFS+1] = FRONT.DAZUNIT[1];	/* for `return box' */
   XCONNECT.RBOX[XCONNECT.OFFR] = mail_in[0];		/* last sender unit */
   XCONNECT.RBOX[XCONNECT.OFFR+1] = mail_in[1];

   nn = sprintf(KAUX.STR,"Status = %d,%d",    /* get status of last applic. */
         KIWORDS[OFF_PRSTAT],KIWORDS[OFF_PRSTAT+1]);

   if (outpid == -1)			/* if we have no sender Pid */
      {					/* we need an intermediate file  */
      fp = osaopen("receive_dummy",WRITE); 		/* open for writing  */
      if (fp == -1)
         {
         time = TIMS;                      /* wait some time + try again */
         sleep(time);

         fp = osaopen("receive_dummy",WRITE); 		/* open for writing  */
         if (fp == -1)
            {
            (void)printf("Could not create intermediate file for RBOX\n");
            return (-2);
            }
         }

      osawrite(fp,KAUX.STR,nn);			/* send succ/error back */
      osaclose(fp);

      stat = osfrename("receive_dummy",XCONNECT.RBOX);	/* move to real name */
      if (stat != 0)
         {
         time = TIMS;                      /* wait some time + try again */
         sleep(time);

         stat = osfrename("receive_dummy",XCONNECT.RBOX);
         if (stat != 0)
            {
            (void)printf("Could not build file %s ...\n\r",XCONNECT.RBOX);
            return (-2);
            }
         }
      }

   else					/* with Pid we use signals */
      {					/* for synchronization */
      fp = osaopen(XCONNECT.RBOX,WRITE); 
      if (fp == -1)
         {
         time = TIMS;                      /* wait some time + try again */
         sleep(time);

         fp = osaopen(XCONNECT.RBOX,WRITE); 
         if (fp == -1)
            {
            (void)printf("Could not create file %s ...\n\r",XCONNECT.RBOX);
            return (-2);
            }
         }

      osawrite(fp,KAUX.STR,nn);			/* send succ/error back */
      osaclose(fp);

      osssend(outpid,SIGUSR2);     /*  indicate to sender, that we're ready */
      }

   if (flag > 7)  return(0);		/* if flag = 8,9  we just quit */
   }


/* besides looking for a file we also wait for SIGUSR1 - just in case */

wait:
fp = osaopen(XCONNECT.SBOX,READ); 			/* open for reading  */
if (fp == -1)
   {
   YesSignal = 0;
   osscatch(SIGUSR1,intdum1);		/* catch the mail signal */
   osswait(SIGUSR1,server.SLEEP);	/* wait at most server.SLEEP seconds */
   goto wait;
   }

nn = osaread(fp,LINE.STR,MAX_LINE);		/* get Midas command */
if (nn <= 0)
   {
   osaclose(fp);
   (void)printf("We have no data in file %s ...\n",XCONNECT.SBOX);
   return (-2);
   }
else if (nn > MAX_LINE)			/* truncate at MAX_LINE chars.  */
   LINE.STR[MAX_LINE-1] = '\0';
 

/*  now get sender Pid  -  but this Pid is NOT required ... */

outpid = -1;				/* init to -1 */
nn = osaread(fp,cptr,20);
if (nn > 0) nn = sscanf(cptr,"%d",&outpid);

osaclose(fp);				/* close send_box */


show_cmnd:
mail_in[0] = LINE.STR[0]; 		/* separate sender unit */
mail_in[1] = LINE.STR[1];

LINE.LEN = CGN_COPY(LINE.STR,&LINE.STR[2]);
file_in = 1;				/* raise flag  */
 
if (KIWORDS[OFF_PRSTAT] != 0)
   {
   KIWORDS[OFF_PRSTAT+5] = KIWORDS[OFF_PRSTAT];
   KIWORDS[OFF_PRSTAT] = 0;		/* save + clear status */
   }


if (server.ECKO == 'Y')			/* display sender info */
   {
   (void)sprintf(KAUX.STR, "-> sender: %2.2s (%d chars.)",mail_in,LINE.LEN);
   (void)printf("%s\n",KAUX.STR);
   (void)printf("%s\n",LINE.STR);		/* display command line sent */
   }
else
   {
   if (MONIT.ENV != 'P')		/* if not PyMidas... */
      {
      nn = LINE.LEN - 8;			/* length of "XCONNECT" */
      if (strcmp(&LINE.STR[nn],"XCONNECT") != 0)
         (void)printf("%s\n",LINE.STR);	/* show only `normal' command line */
      }
   }
ERRORS.OFFSET = 0;

if (server.MODE != 1)
   {
   stat = osfdelete(XCONNECT.SBOX);                  /* delete send frame */
   if (stat != 0)
      {
      time = TIMS;                      /* wait some time + try again */
      sleep(time);

      stat = osfdelete(XCONNECT.SBOX);                  /* delete send frame */
      if (stat != 0)
         {
         (void)printf("Could not delete send_box %s ...\n",XCONNECT.SBOX);
         return (-2);
         }
      }
   }

return (0);
}

/*

*/

void busymail()

{
int   fp, nn;
int   time, busypid;
  
char  cptr[80], busyunit[8];



XCONNECT.SBOX[XCONNECT.OFFS] = FRONT.DAZUNIT[0];    /* insert our Midas unit */
XCONNECT.SBOX[XCONNECT.OFFS+1] = FRONT.DAZUNIT[1];

fp = osaopen(XCONNECT.SBOX,READ);              /*  open for reading  */
if (fp == -1) 
   {
   time = TIMS;                      /* wait some time + try again */
   sleep(time);

   fp = osaopen(XCONNECT.SBOX,READ);              /*  open again */
   if (fp == -1)
      {
      (void)printf("we could not find send_box: %s\n",XCONNECT.SBOX);
      return;				/* we're out of sync - ignore */
      }
   }

nn = osaread(fp,busyunit,4);		/* get sender unit */
if (nn <= 0) 
   {
   (void)printf("we could not read send_box: %s\n",XCONNECT.SBOX);
   osaclose(fp); 
   return;		
   }


/*  now get sender Pid  -  but this Pid is NOT required ... */

busypid = -1;                            /* init to -1 */
nn = osaread(fp,cptr,20);
if (nn > 0) nn = sscanf(cptr,"%d",&busypid);
osaclose(fp);                           /* close send_box */

XCONNECT.RBOX[XCONNECT.OFFS] = FRONT.DAZUNIT[0];    /* insert Midas unit  */
XCONNECT.RBOX[XCONNECT.OFFS+1] = FRONT.DAZUNIT[1];  /* to build `return box' */
XCONNECT.RBOX[XCONNECT.OFFR] = busyunit[0];
XCONNECT.RBOX[XCONNECT.OFFR+1] = busyunit[1];

nn = sprintf(cptr,"BUSY - BUSY - BUSY (MIDAS unit %c%c)", /* return message */
      FRONT.DAZUNIT[0],FRONT.DAZUNIT[1]);

if (busypid == -1)                    /* if we have no sender Pid */
   {                                  /* we need an intermediate file  */
   fp = osaopen("receive_dummy",WRITE);                /*  open for writing  */
   if (fp == -1)
      {
      time = TIMS;                      /* wait some time + try again */
      sleep(time);

      fp = osaopen("receive_dummy",WRITE);		/*  open again */
      if (fp == -1)
         {
         (void)printf("we could not create temp file: %s\n",XCONNECT.RBOX);
         return;      
         }
      }

   osawrite(fp,cptr,nn);
   osaclose(fp);
   osfrename("receive_dummy",XCONNECT.RBOX);      /* move to real name */
   }

else                                 /* with Pid we use signals */
   {                                 /* for synchronization */
   fp = osaopen(XCONNECT.RBOX,WRITE);                  /*  open for writing  */
   if (fp == -1) 
      {
      time = TIMS;                      /* wait some time + try again */
      sleep(time);
   
      fp = osaopen(XCONNECT.RBOX,WRITE);		/*  open again  */
      if (fp == -1) 
         (void)printf("we could not create receive_box: %s\n",XCONNECT.RBOX);
      }
   else
      {
      osawrite(fp,cptr,nn);
      osaclose(fp);
      }
   osssend(busypid,SIGUSR2);     /*  indicate to sender, that we're ready */
   }
}

/*

*/
 
void trigback(idx)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 activate bkstat of entry `idx' in BKMIDAS structure
.ALGORITHM
.RETURNS
 nothing
-----------------------------------------------------------------*/
int   idx;		/* IN: index into BKMIDAS structure */


{
bkstat[idx] = 1;
}



int showback(munit,disp)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 show contents of BKMIDAS structures
.ALGORITHM
.RETURNS
 status of `unit' (status of last backgr. Midas if `unit' = '?' or '*')
-----------------------------------------------------------------*/
char  *munit;		/* IN: background unit,
			       if = ? or = * show all backgr. Midas */
int   disp;		/* IN: = 0, no display,
			       = 1  display info on terminal 
				 only used for flag = 0  */

{
register int  nr, mr;
int    idum[2], kk, jj, limit, retstat;

char   save[4], wstr[84], myunit[4];
char   ua, ub;




if ((*munit != '?') && (*munit != '*'))
   {
   ua = *munit++;
   ub = *munit;

   for (mr=0; mr<MAX_BACK; mr++)
      {
      if ((BKMIDAS[mr].UNIT[0] == ua) && (BKMIDAS[mr].UNIT[1] == ub))
         {
         limit = mr + 1;
         goto show_back;
         }
      }
   }

else
   {
   ua = '\0';
   for (mr=0; mr<MAX_BACK; mr++)
      {
      if (BKMIDAS[mr].UNIT[0] != ' ')
         {
         limit = MAX_BACK;
         goto show_back;
         }
      }
   }

if (disp == 1) SCTPUT("no Background Midas connected...");
return (-1);			/* return not_possible status */


show_back:

retstat = 0;
if (disp == 1)
   {
   SCTPUT("unit char wait secs  pid/osxid  method  status ");
   SCTPUT("-----------------------------------------------");
   }

for (nr=mr; nr<limit; nr++)
   {
   if (BKMIDAS[nr].UNIT[0] != ' ')
      {
      if (BKMIDAS[nr].METHOD == 's')	/* check status of backgr. Midas */
         {
         jj = BKMIDAS[nr].CHAN;
         if (bkstat[nr] != 0)		/* only check, if was busy or set */
            {
            bkstat[nr] = outmail(3,wstr,nr,idum);
            if (bkstat[nr] == 0) 		/* synchronize the 1. time */
               outmail(4,wstr,nr,idum);		/* status is idle */
            }
         }
      else
         {
         jj = BKMIDAS[nr].PID;
         bkstat[nr] = outmail(3,wstr,nr,idum);	/* always get status */
         }

      retstat = bkstat[nr];			/* save return status */

      if (disp == 1)
         {
         myunit[0] = BKMIDAS[nr].UNIT[0];
         myunit[1] = BKMIDAS[nr].UNIT[1];
         myunit[2] = '\0';

         if (BKMIDAS[nr].FLAG == 'Y')
            {
            (void)strcpy(save,"Yes");
            kk = BKMIDAS[nr].WAIT;
            if (kk >= 0)
               (void)sprintf(wstr,"%s    %c   %s  %4.4d   %5.5d",
                             myunit,BKMIDAS[nr].COMC,save,kk,jj);
            else
               (void)sprintf(wstr,"%s    %c   %s  inf    %5.5d",
                             myunit,BKMIDAS[nr].COMC,save,jj);
            }
         else
            {
            (void)strcpy(save,"No ");
            (void)sprintf(wstr,"%s    %c   %s         %5.5d",
                          myunit,BKMIDAS[nr].COMC,save,jj);
            }
         if (BKMIDAS[nr].METHOD != 's')
            (void)strcat(wstr,"     files  ");
         else
            (void)strcat(wstr,"     sockets");

         if (retstat == 0)
            (void)strcat(wstr,"  idle             ");
         else if (retstat == 1)
            (void)strcat(wstr,"  busy             ");
         else if (retstat == 2)
            (void)strcat(wstr,"  timed out        ");
         else if (retstat == 3)
            (void)strcat(wstr,"  last_com ignored ");
         else
            {
            char  wwstr[40];

            (void)sprintf(wwstr,"  comm. problem (%d)",retstat);
            (void)strcat(wstr,wwstr);
            }

         if (BKMIDAS[nr].HOST[0] != '\0')
            {
            (void)strcat(wstr,"on host: ");
            (void)strcat(wstr,BKMIDAS[nr].HOST);
            }
         else
            (void)strcat(wstr,"on localhost");

         SCTPUT(wstr);
         }
      }
   }

return (retstat);
}

/*

*/
 
void waitback(token,retstat)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 wait for background Midas 
.ALGORITHM
.RETURNS
-----------------------------------------------------------------*/

char  *token;		/* IN: backgr. Midas unit */
int   retstat[2];	/* OUT: return status from background Midas */

{

int  n;


if (token[0] == '?')                /* wait for all outstanding mails */
   {
   for (n=0; n<MAX_BACK; n++)
      {
      if (BKMIDAS[n].ACTIVE == 'A')
         {
         if (BKMIDAS[n].HOST[0] != '\0')
            (void)sprintf(KAUX.STR,"waiting for MIDAS unit %c%c on host %s\n",
                    BKMIDAS[n].UNIT[0],BKMIDAS[n].UNIT[1],
                    BKMIDAS[n].HOST);
         else
            (void)sprintf(KAUX.STR,"waiting for MIDAS unit %c%c\n",
                    BKMIDAS[n].UNIT[0],BKMIDAS[n].UNIT[1]);
         SCTPUT(KAUX.STR);
         outmail(2,KAUX.STR,n,retstat);
         }
      }
   }
else
   {
   for (n=0; n<MAX_BACK; n++)
      {
      if ((BKMIDAS[n].UNIT[0] == token[0]) &&
          (BKMIDAS[n].UNIT[1] == token[1]))
         {
         outmail(2,KAUX.STR,n,retstat);
         break;
         }
      }
   }
}

/*

*/
 
int setback(token)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 set Midas into background mode using sockets
.ALGORITHM
.RETURNS
 status from osx
-----------------------------------------------------------------*/

char  *token;		/* IN: method (FILES or SOCKET or SOCKET,REMOTE) */

{
int  n, reto;



n = CGN_INDEXC(token,',') + 1;
if ( (n > 1) && ((token[n] == 'r') || (token[n] == 'R')) )
   {
   n = ServInit("network",&reto);		/* remote host */
   if (n == 0)
      (void) printf("Now in background mode (via network sockets)\n");
   else
      n = reto;
   }
else
   {
   n = ServInit("",&reto);		/* local host */
   if (n == 0)
      (void) printf("Now in background mode (via local sockets)\n");
   else
      n = reto;
   }

return (n);
}
