/*===========================================================================
  Copyright (C) 1994-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
===========================================================================*/

/*+++++++++++++++++++++++ module consubs +++++++++++++++++++++++
.LANGUAGE C
.IDENTIFICATION Module consubs
.AUTHOR         K. Banse  ESO - Garching
.KEYWORDS
  connection, sockets
.COMMENTS
  holds  msetup, outmail
.ENVIRONMENT  UNIX

.VERSION  [1.00] 940426:  pulled out from prepb.c

 090407		last modif

------------------------------------------------------------------------*/
 
#include <midas_def.h>
#include <stdio.h>
#include <signal.h>

#ifndef SIGUSR1
#define SIGUSR1 30
#endif

#ifndef SIGUSR2
#define SIGUSR2 31
#endif

#include <osyparms.h>
#include <xconndef.h>

#define  WRITE 1
#define  READ  0

static int YesSignal;



void intdum2()

{

YesSignal = 2;

}


/*

*/
 
int msetup(flag,token1,token2,token3,token4)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 setup data for background activities
 flag = 0	DISCONNECT/BACK unit
      = 1	CONNECT/BACK unit ...
.ALGORITHM
.RETURNS
        =   0; all o.k.
        =   4; problems with socket communication
        =  34; BKMIDAS structure overflow
        =  90; invalid unit (FORGRxy.PID not found)
        = 100; invalid seconds

-----------------------------------------------------------------*/

int   flag;

char  *token1;		/* IN: backgr. Midas unit */
char  *token2;		/* IN: `wait,seconds' string */
char  *token3;		/* IN: background char. */
char  *token4;		/* IN: connection method, `files' or `sockets' */


{
register int  nr, mr;
int    fid, iwc, kk, jj, reto;
int    idum;

float   rdum;

double  ddum;

char   save[4], cbuf[20], wstr[84];


if (flag == 0)
   {					/* clear background-Midas table */
   if ((token1[0] == '?') || (token1[0] == '*'))
      {
      for (nr=0; nr<MAX_BACK; nr++)
         {
         for (mr=0; mr<MAX_BACK; mr++)
            BKMIDAS[mr].ACTIVE = 'N';		/* deactivate all */
         if (BKMIDAS[nr].UNIT[0] != ' ')
            {
            if (BKMIDAS[nr].METHOD == 's') 
               {
               if (ClientClose(BKMIDAS[nr].CHAN,&reto) != 0)
                  goto bad_osxclose;
               }
            BKMIDAS[nr].UNIT[0] = ' ';
            }
         }
      return (0);
      }

   else
      {
      for (nr=0; nr<MAX_BACK; nr++)
         {
         if ((token1[0] == BKMIDAS[nr].UNIT[0]) &&
             (token1[1] == BKMIDAS[nr].UNIT[1])) 
            {
            BKMIDAS[nr].ACTIVE = 'N';		/* deactivate it */
            if (BKMIDAS[nr].METHOD == 's') 
               {
               if (ClientClose(BKMIDAS[nr].CHAN,&reto) != 0)
                  goto bad_osxclose;
               }
            BKMIDAS[nr].UNIT[0] = ' ';
            }
         }
      return (0);
      }

bad_osxclose:
   token1[0] = BKMIDAS[nr].UNIT[0];
   token1[1] = BKMIDAS[nr].UNIT[1];
   token1[2] = '\0';
   BKMIDAS[nr].UNIT[0] = ' ';
   return (4);
   }

else if (flag == 1)
   {				/* work on background MIDAS table */
   save[2] = CGN_LOWER(token2[0]);		/* wait,secs */
   cbuf[0] = CGN_LOWER(token3[0]);		/* b_char.  */
   cbuf[1] = CGN_LOWER(token4[0]);		/* method   */

   if (cbuf[1] != 's') cbuf[1] = 'f';

   jj = CGN_INDEXC(token1,':');		/* check if remote host */
   if (jj > 0)
      {                                 /* remote host  */
      token1[jj] = '\0';          /* ':' -> '\0'  */
      nr = jj + 1;
      }
   else
      nr = 0;
 
   save[0] = CGN_UPPER(token1[nr++]);
   save[1] = CGN_UPPER(token1[nr]);

   if (save[2] == 'w')
      {
      save[2] = 'Y';
      kk = CGN_INDEXC(token2,',');
      if (kk > 0)
         {
         iwc = CGN_CNVT(&token2[kk+1],1,1,&idum,&rdum,&ddum);
         if (iwc == 1)
            kk = idum;
         else
            kk = -1;				/* that's an error */
         if (kk < 0)
            {
            return (100);
            }
         }
      else
         kk = -1;
      }
   else
      {
      save[2] = 'N';
      kk = 0;
      }

   for (nr=0; nr<MAX_BACK; nr++)      /* see, if already same entry there */
      {
      if (jj > 0)			/* remote MIDAS unit */
         {
         if (strcmp(BKMIDAS[nr].HOST,token1) == 0) 
            {
            if ( (BKMIDAS[nr].UNIT[0] == save[0]) &&
                 (BKMIDAS[nr].UNIT[1] == save[1]) &&
                 (BKMIDAS[nr].COMC == cbuf[0]) )
               {
               iwc = nr;
               goto get_backpid;
               }
            }
         }
      else
         {
         if (BKMIDAS[nr].HOST[0] == '\0') 
            {
            if ( (BKMIDAS[nr].UNIT[0] == save[0]) &&
                 (BKMIDAS[nr].UNIT[1] == save[1]) &&
                 (BKMIDAS[nr].COMC == cbuf[0]) ) 
               {
               iwc = nr;
               goto get_backpid;
               }
            }
         }
      }

   for (nr=0; nr<MAX_BACK; nr++)		/* look for free slot */
      {
      if (BKMIDAS[nr].UNIT[0] == ' ')
         {
         iwc = nr;
         goto get_backpid;
         }
      }
   return (34);                         /* no more space */

  get_backpid:
   BKMIDAS[iwc].UNIT[0] = save[0];
   BKMIDAS[iwc].UNIT[1] = save[1];
   BKMIDAS[iwc].WAIT = kk;
   BKMIDAS[iwc].COMC = cbuf[0];
   BKMIDAS[iwc].METHOD = cbuf[1];
   BKMIDAS[iwc].FLAG = save[2];	
   BKMIDAS[iwc].ACTIVE = 'N';
   BKMIDAS[iwc].PID = -1;
   if (jj > 0)
      (void)strcpy(BKMIDAS[iwc].HOST,token1);
   else
      BKMIDAS[iwc].HOST[0] = '\0';

   if (BKMIDAS[iwc].METHOD != 's')         /* for interrupts we need the PID */
      {
      kk = CGN_COPY(wstr,XCONNECT.SBOX);
      kk -= 12;					/* get rid of FORGRxy.SBOX */
      (void)strcpy(&wstr[kk],"MIDAS  .PID");
      wstr[kk+5] = BKMIDAS[iwc].UNIT[0];
      wstr[kk+6] = BKMIDAS[iwc].UNIT[1];
      fid = osaopen(wstr,READ);                 /* open to read */
      if (fid > 0)
         {
         kk = osaread(fid,wstr,40);
         if (kk > 0) (void)sscanf(wstr,"%d",&BKMIDAS[iwc].PID);
         (void)osaclose(fid);
         }
       
      if (BKMIDAS[iwc].PID == -1)
         return (90);			/* could not read MIDASxy.PID */
      }
   else
      {
      cbuf[0] = BKMIDAS[iwc].UNIT[0];
      cbuf[1] = BKMIDAS[iwc].UNIT[1];
      cbuf[2] = '\0';
      kk = ClientInit(BKMIDAS[iwc].HOST,cbuf,&BKMIDAS[iwc].CHAN,&reto);
      if (kk == -1) return (4);		/* no connection ... */
      }
   }

return (0);
}

/*

*/

int outmail(flag,comline,bgindx,retstat)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  send single line via file "FORGRxy.SBOX" to a `background' MIDAS
  and wait for receive_box
.ALGORITHM
.RETURNS
 	=  0; all o.k.
	=  1; background is busy
	=  2; timed out
	=  3; background was busy + ignored last command sent
	=  4; problems with osx, `oserror' in retstat[0]
	=  5; problems with file/interrupts, specific error in retstat[0]
	=  7; socket connection was closed by command sent 
	=  9; nothing to wait for  (flag = 2)
-----------------------------------------------------------------*/

int flag;		/* IN: 1 = send command with/without wait    
			       2 = only wait        
			       3 = check, if finished */
char  *comline;		/* IN: command line to send */
int   bgindx;		/* IN: index in BKMIDAS */
int   retstat[2];	/* OUT: return status (2 vals) from Background Midas */

{
int   tmout, fp, send_more, reto;
int   nn, kk, jj, wasbusy;

float   rdum;
double  ddum;

char  frname[80];



/* insert unit into relevant files */

if (BKMIDAS[bgindx].METHOD == 'f')	/* files/interrupt service */
   {
   XCONNECT.SBOX[XCONNECT.OFFS] = BKMIDAS[bgindx].UNIT[0];
   XCONNECT.SBOX[XCONNECT.OFFS+1] = BKMIDAS[bgindx].UNIT[1];
   XCONNECT.RBOX[XCONNECT.OFFS] = XCONNECT.SBOX[XCONNECT.OFFS];
   XCONNECT.RBOX[XCONNECT.OFFS+1] = XCONNECT.SBOX[XCONNECT.OFFS+1];
   XCONNECT.RBOX[XCONNECT.OFFR] = XCONNECT.MYUNIT[0];	/* return address.. */
   XCONNECT.RBOX[XCONNECT.OFFR+1] = XCONNECT.MYUNIT[1];
   }
send_more = 0;
wasbusy = 0;
retstat[1] = 0;


/* for flag=2, we wait on given unit until finished */

if (flag == 2)
   {
   if (BKMIDAS[bgindx].ACTIVE != 'N')
      {
      if (BKMIDAS[bgindx].METHOD == 'f')	/* files/interrupt service */
         {
       w_loop:
         fp = osaopen(XCONNECT.RBOX,READ);        /* so, see if already done */
         if (fp == -1)
            {
            OSY_SLEEP(100,1);		/* wait .1 sec. */
            goto w_loop;
            }
         else
            goto read_rbox;
         }
      else
         {
         jj = ClientWait(BKMIDAS[bgindx].CHAN,-1);	/* wait forever */
         if (jj == -1) return (4);

         goto read_socket;
         }
      }
   return (9);		/* nothing there to wait for */
   }


/* for flag=3, we just check on given unit */

else if (flag == 3)
   {
   if (BKMIDAS[bgindx].METHOD == 'f')       /* files/interrupt service */
      {
      if (BKMIDAS[bgindx].ACTIVE != 'N')
         {
         fp = osaopen(XCONNECT.RBOX,READ);         /* see if already done */
         if (fp != -1)
            {
            kk = osaread(fp,frname,72);                     /*  read a line */
            (void)osaclose(fp);
            if (kk < 1) return (5);
             
            if (strncmp(frname,"BUSY",4) == 0)	   /* check for busy status */
               return (1);
            }
         else
            return (1);
         }
      }
   else
      {
      jj = ClientWait(BKMIDAS[bgindx].CHAN,0);		/* just check */
      if ((BKMIDAS[bgindx].ACTIVE != 'N') && (jj == 0)) 
         return (1);				/* NODATA means it's busy */
      if (jj == -1) return (4);
      }
   BKMIDAS[bgindx].ACTIVE = 'N';
   return (0);
   }


/* for flag=4, we read termination status of last command */

else if (flag == 4)
   {
   BKMIDAS[bgindx].ACTIVE = 'N';		/* always clear entry */
   
   if (BKMIDAS[bgindx].METHOD == 'f')		/* files/interrupt service */
      {
      fp = osaopen(XCONNECT.RBOX,READ);		/* open for reading */
      if (fp == -1) return (5);

      kk = osaread(fp,frname,72);                     /*  read a line */
      (void)osaclose(fp);
      if (kk < 1)
         {
         *retstat = -2;
         return (5);
         }

      /* now pull out the status info */

      kk = CGN_INDEXC(frname,'=') + 2;		/* Status = `status'  */
      if (kk > 1)
         {
         if ((frname[kk] != '0') || (frname[kk+1] != '\0'))
            {
            nn = CGN_CNVT(&frname[kk],1,2,retstat,&rdum,&ddum);
            if (nn < 2)
               {
               *retstat = -3;
               return (5);
               }
            }
         else
            *retstat = 0;
         }
      else
         {
         *retstat = -3;
         return (5);                          /* strange Receive Box */
         }
      }

   else
      {
      kk = ClientRead(BKMIDAS[bgindx].CHAN,frname,&jj,&reto);
      if (kk != 0)
         {
         *retstat = reto;
         return (4);
         }

      *retstat = jj;
      }
   return (0);
   }



/* for flag=1, we send a command 
   check, if we're still using same background Midas */

if (BKMIDAS[bgindx].ACTIVE != 'N')
   {
   send_more = 1;			/* mark that we still have to send */

   if (BKMIDAS[bgindx].METHOD == 'f')		/* files/interrupt service */
      {
      fp = osaopen(XCONNECT.RBOX,READ);		/* so, see if already done */
      if (fp == -1) return (1);

      goto read_rbox;
      }
   else
      {
      jj = ClientWait(BKMIDAS[bgindx].CHAN,0);	
      if (jj == -1) 
         return (4);
      else if (jj == 0)
         return (1);
      else
         goto read_socket;
      }
   }


/* o.k. it's an idle guy, so make this entry active  
   and send via `osx' or create FORGRbk.SBOX */

send_mail:
BKMIDAS[bgindx].ACTIVE = 'A';

if (BKMIDAS[bgindx].METHOD == 's')
   {
   nn = BKMIDAS[bgindx].CHAN;
   kk = ClientWrite(nn,comline,&reto);	/* send via osx + return */
   if (kk != 0) 
      {
      *retstat = reto;
      return (4);
      }
   if (BKMIDAS[bgindx].FLAG == 'N')
      {
      *retstat = 0;
      return (wasbusy);		/* if we send without wait, that's it... */
      }
 
   jj = ClientWait(BKMIDAS[bgindx].CHAN,BKMIDAS[bgindx].WAIT);
   if (jj != 1) return (2);                   /* we waited the whole time */

read_socket:
   BKMIDAS[bgindx].ACTIVE = 'N';		/* always clear entry */

   kk = ClientRead(BKMIDAS[bgindx].CHAN,frname,&jj,&reto);
   if (kk == -1) 
      {
      *retstat = reto;
      return (4);
      }
   else if (jj == 99) 	/* connection was closed by the command we sent */
      return (7);

   if (send_more == 1) 
      {
      send_more = 0;		/* clear flag again */
      goto send_mail;		/* we still have to send our stuff  */
      }
    
   *retstat = jj;
   return (0);
   }


/* ASCII file + interrupt section */

kk = osfdelete(XCONNECT.RBOX);		/* try to delete own old receive box */

fp = osaopen("dummy",WRITE);		/* create send_box  */
if (fp == -1)
   {
   *retstat = -1;
   return(5);
   }

osawrite(fp,comline,(int)strlen(comline));
(void)sprintf(frname,"%d",XCONNECT.MYPID);		/* write own Pid  */
osawrite(fp,frname,(int)strlen(frname));
(void)osaclose(fp);
osfrename("dummy",XCONNECT.SBOX);	/* move to real name */



if (BKMIDAS[bgindx].PID != -1) osssend(BKMIDAS[bgindx].PID,SIGUSR1);
osscatch(SIGUSR2,intdum2); 
if (BKMIDAS[bgindx].FLAG == 'N')
   {
   *retstat = 0;
   return (wasbusy);		/* if we send without wait, that's it... */
   }

if (BKMIDAS[bgindx].WAIT != -1)
   tmout = BKMIDAS[bgindx].WAIT;
else
   tmout = 1;				/* initial timeout for osswait */


/* now we wait until Backgr. Midas finishes */

wait:
YesSignal = 0;
osswait(SIGUSR2,tmout);		/* wait max. `tmout' secs */

fp = osaopen(XCONNECT.RBOX,READ);		/* open for reading */
if (fp == -1) 
   {
   if ((BKMIDAS[bgindx].WAIT != -1) && (YesSignal == 0))
      {
      (void)osscatch(SIGUSR2,intdum2); 	/* in case, signal comes later */
      return (2);                          /* we waited the whole time */
      }
   else
      {
      tmout = 5;				/* new timeout for osswait */
      (void)osscatch(SIGUSR2,intdum2); 
      goto wait;
      }
   }


/* read RBOX and get the return status */

read_rbox:
BKMIDAS[bgindx].ACTIVE = 'N';				/* clear entry */

kk = osaread(fp,frname,72); 			/*  read a line */
(void)osaclose(fp);
if (kk < 1) 
   {
   *retstat = -2;
   return (5);
   }

if (strncmp(frname,"BUSY",4) == 0)		/* background MIDAS was busy */
   {
   if (send_more == 1) 
      {
      wasbusy = 3;
      send_more = 0;			/* clear flag again */
      goto send_mail;		/* we still have to send our stuff  */
      }
   else
      return (1);
   }


if (send_more == 1) 
   {
   send_more = 0;			/* clear flag again */
   goto send_mail;		/* we still have to send our stuff  */
   }


/* pull out status info */

kk = CGN_INDEXC(frname,'=') + 2;		/* Status = `status'  */
if (kk > 1)
   {
   if ((frname[kk] != '0') || (frname[kk+1] != '\0'))
      {
      nn = CGN_CNVT(&frname[kk],1,2,retstat,&rdum,&ddum);   
      if (nn < 2) 
         {
         *retstat = -3;
         return (5);
         }
      }
   else
      *retstat = 0;
   }
else
   {
   *retstat = -3;
   return (5);				/* strange Receive Box */
   }


return (wasbusy);
}

