/*
    it's a FINITE_STATE_MACHINE which handles the state of the
                    conversation.

                      FSM_CONV
 Function: handels the state of the conversation resource.
           There may be the following states:
        - RESET;
        - SEND;
        - Rcv=receive;
        - RCVD_CONFIRM=received confirm;
        - RCVD_CONFIRM_SEND=received confirm send;
        - RCVD_CONFIRM_DEALL=received confirm deallocate;
        - PREP_TO_RCV_DEFER=prepare to receive defer;
        - DEALL_DEFER=deallocate defer;
        - PEND_DEALL=pending deallocate.

 Note that the PEND_DEALL is an intermedia state, in that case LU does not
 returns control to the transaction program.

  CopyRight 1995. Nicholas Poljakov all rights reserved.
*/

#include <stdio.h>
#include <malloc.h>
#include <state1.h>
#include <rcb.h>
#include <lucb.h>
#include <string.h>

#define Remote 114
#define Slocal 115
int sk_r_wt(void *);
int SendBlock(void *, void *);
int setrc(void *, void *);
int sendhsf(void *);
int sendhs(void *);
int sendbm(void *, void *);
int sendat(void *);
int rtsend(void *);
unsigned long rmfmh5(void *, void *);
int recwait(void *);
int rcvru(void *, void *);
int rcvhs(void *, void *, void *, void *);
int ralloc(void *, void *);
int psrm(int, void *, void *);
int ps_conv(int, void *);
int proterr(void *, unsigned long);
int preptrcv(void *, void *);
int post_rcb(void *);
struct repass *postopen(void *);
int phsrec(void *);
int pfmh5(void *);
int opndst(void *);
int obtsess(void *, unsigned char);
int Lrf_handler(void *);
int get_sess(void *, void *);
int get_attr(void *);
int fsm_error(unsigned char, void *);
int flush (void *);
int dcp(void *);
int dealloc(void *);
int crtp(void *);
int conv(void *);
int chkparm(void *, void *);
int check_end(unsigned int, void *);
struct rqb *call_appl(void *);
int buffmng(unsigned char, void *, void *, void *, unsigned, unsigned char, unsigned);
unsigned long attltck(void *);
unsigned long attacheck(void *);
char *cgetmem(int, int);
int sendhsf(void *);
int opndst(void *);
int alloc_rcb(void *, void *);
int allocate(void *);
int clsdst(void *);

int fsm_conv(p1,p2,p_rcb)
 unsigned char p1;
 unsigned char p2;
 struct rcb *p_rcb;
{
 struct tcb *p_tcb;
 unsigned char type;
 char *p;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;           /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "fsmconv");
pnum = 1;
lenr = sizeof(struct rcb) + 2;
drec = malloc(lenr);
drec[0] = p1;
drec[1] = p2;
p = drec + 2;
memcpy(p, p_rcb, lenr - 2);
gtf(rtype, pname, pnum, drec, lenr);
free(drec);
/***********************************/
#endif

  if((p1 == 'r')||(p1 == 'R'))
  p1=Remote;
  if((p1 == 's')||(p1 == 'S'))
  p1=Slocal;

 switch(p1)
   {
   case Remote:
      switch (p2)
        {
	case ATTACH:
          {
              if(p_rcb->conv_state==RESET)
              {
                  p_rcb->conv_state = Rcv;
                  goto ex0;
              }
              else
                  {
                     goto ex_1;
                  }
          }
    case send_indicator:
         {
             if(p_rcb->conv_state==Rcv) {
                 p_rcb->conv_state = SEND;
                 goto ex0;
             }
               else
                       {
                          goto ex_1;
                       }
         }
    case confirm_indicator:
         {
             if(p_rcb->conv_state==Rcv) {
                 p_rcb->conv_state = rcvd_confirm;
                 goto ex0;
             }
               else
                       {
                           goto ex_1;
                       }
          }
    case confirm_send_ind:
          {
              if(p_rcb->conv_state==Rcv) {
                p_rcb->conv_state = rcvd_confirm_send;
                goto ex0;
              }
                else
                        {
                            goto ex_1;
                        }
          }
    case confirm_dealloc_ind:
         {
              if(p_rcb->conv_state==Rcv) {
                p_rcb->conv_state = rcvd_confirm_deall;
                goto ex0;
              }
                else
                        {
                            goto ex_1;
                        }
         }
    case program_error_rc:
    case service_error_rc:
       {
            switch (p_rcb->conv_state)
                   {  case RESET:
                      case rcvd_confirm:
                      case rcvd_confirm_send:
                      case rcvd_confirm_deall:
                      case END_CONV:
                                           goto ex_1;
                      case SEND:
                      case PREP_TO_RCV_DEFER:
                      case Deallocate_defer:
                      case pend_deall:
                                       {
                                           p_rcb->conv_state = Rcv;
                                             fsm_error(RESET, p_rcb);
                                             goto ex0;
                                       }
                      case Rcv:
                                       {
                                           fsm_error(RESET, p_rcb);
                                           goto ex0;
                                       }
                   }
       }
    case Dealloc_normal_rc:
       {
           if((p_rcb->conv_state == SEND)||(p_rcb->conv_state==Rcv)) {
               p_rcb->conv_state = END_CONV;
               goto ex0;
           }
             else { goto ex_1; }
       }
    case Dealloc_abend_rc:
    case RESOURCE_FAILURE_RC:
    case ALLOCATION_ERROR_RC:
       {
        if((p_rcb->conv_state == SEND)||(p_rcb->conv_state==Rcv)||
            (p_rcb->conv_state == PREP_TO_RCV_DEFER)||
            (p_rcb->conv_state == Deallocate_defer)||
            (p_rcb->conv_state==pend_deall)) {
               p_rcb->conv_state = END_CONV;
               fsm_error(RESET, p_rcb);
               goto ex0;
        }
          else { goto ex_1; }
       }
    case Deallocated_ind:
       {
        if(p_rcb->conv_state == Deallocate_defer) {
            p_rcb->conv_state = RESET;
            goto ex0;
        }
          else { goto ex_1; }
       }
   }
    case Slocal:
     switch (p2)
      {
        case Allocate:
        {
            if(p_rcb->conv_state == RESET) {
                p_rcb->conv_state = SEND;
                goto ex0;
            }
          else { goto ex_1; }
        }
        case Send_data:
        {
            if((p_rcb->conv_state == RESET)||(p_rcb->conv_state==SEND)||
               (p_rcb->conv_state == pend_deall)) {
               if(p_rcb->conv_state == SEND) {
                  goto ex0;
               }
               goto ex_1;
            }
                else
                   {
                     p_tcb = p_rcb -> p_tcb;
                     goto ex1;
                   }
        }
        case PREP_TO_RCV_FLUSH:
        case PREP_TO_RCV_CONFIRM_SH:
        case PREP_TO_RCV_CONFIRM_LG:
        {
            if((p_rcb->conv_state == RESET)||(p_rcb->conv_state==SEND)||
              (p_rcb->conv_state == pend_deall)) {
                if(p_rcb->conv_state == SEND) {
                    p_rcb->conv_state=Rcv;
                    goto ex0;
                }
                goto ex_1;
            }
               else
               {
                 p_tcb = p_rcb -> p_tcb;
                 goto ex1;
               }
        }
        case PREP_TO_RCV_DEFER:
        {
            if((p_rcb->conv_state == RESET)||(p_rcb->conv_state==SEND)||
               (p_rcb->conv_state == pend_deall)) {
               if(p_rcb->conv_state == SEND) {
                  p_rcb->conv_state=PREP_TO_RCV_DEFER;
                  goto ex0;
               }
               goto ex_1;
            }
               else
               {
                 p_tcb = p_rcb -> p_tcb;
                 goto ex1;
               }
        }
        case Flush:
        case Confirm:
                     switch (p_rcb->conv_state)
                      {
                        case RESET:
                        case pend_deall:
                            {
                                goto ex_1;
                            }
                        case SEND:
                            {
                                goto ex0;
                            }
                        case Rcv:
                        case rcvd_confirm:
                        case rcvd_confirm_send:
                        case rcvd_confirm_deall:
                        case END_CONV:
                            {
                               p_tcb = p_rcb -> p_tcb;
                               goto ex1;
                            }
                        case PREP_TO_RCV_DEFER:
                            {
                                p_rcb->conv_state = Rcv;
                                goto ex0;
                            }
                        case deall_defer:
                            {
                                 p_rcb->conv_state = pend_deall;
                                 goto ex0;
                            }
                      }
        case Send_error:
                      switch (p_rcb->conv_state)
                            {
                               case RESET:
                               case pend_deall:
                                   {
                                       goto ex_1;
                                   }
                               case SEND:
                                   {
                                       goto ex0;
                                   }
                               case Rcv:
                               case rcvd_confirm:
                               case rcvd_confirm_send:
                               case rcvd_confirm_deall:
                                   {
                                       p_rcb->conv_state = SEND;
                                       goto ex0;
                                   }
                               case PREP_TO_RCV_DEFER:
                               case Deallocate_defer:
                               case END_CONV:
                                   {
                                      p_tcb = p_rcb -> p_tcb;
                                      goto ex1;
                                   }
                            }
        case Receive_and_wait:
      switch (p_rcb->conv_state)
       {
         case RESET:
         case pend_deall:
            {
               goto ex_1;
            }
         case SEND:
            {
                 p_rcb->conv_state = Rcv;
                 if(p_rcb -> send_ll_remainder == 0) {
		     p = (char *)&((*p_rcb).first_out);
                     type = PREP_TO_RCV_FLUSH;
                     buffmng('A', NULL, p, p_rcb, 0, 0, type);
                     sendhsf(p_rcb);
                     goto ex0;
                 }
                  else
                       {
                          p_tcb = p_rcb -> p_tcb;
                          dcp(p_tcb);
                          goto ex0;
                       }
            }
         case Rcv:
            {
              goto ex0;
            }
         case rcvd_confirm:
         case rcvd_confirm_send:
         case rcvd_confirm_deall:
         case PREP_TO_RCV_DEFER:
         case Deallocate_defer:
         case END_CONV:
            {
              p_tcb = p_rcb -> p_tcb;
              goto ex1;
            }
         }
        case Post_on_receipt:
        case Wait:
        case Test:
        case Receive_immediate:
        case Request_to_send:
  {
     if((p_rcb->conv_state == RESET)||(p_rcb->conv_state==Rcv)||
        (p_rcb->conv_state == pend_deall)) {
        if(p_rcb->conv_state == Rcv) {
            goto ex0;
         }
         goto ex_1;
     }
        else
             {
               if(p2==Request_to_send) {
                if(p_rcb->conv_state == rcvd_confirm) {
                    goto ex0;
                }
               }
                  else
                        {
                           p_tcb = p_rcb -> p_tcb;
                           goto ex1;
                         }
             }
  }
	case COnfirmed:
                    switch (p_rcb->conv_state)
                    {
                       case RESET:
                       case pend_deall:
                           {
                               goto ex_1;
                           }
                       case SEND:
                       case Rcv:
                       case PREP_TO_RCV_DEFER:
                       case Deallocate_defer:
                       case END_CONV:
                           {
                              p_tcb = p_rcb -> p_tcb;
                              goto ex1;
                           }
                       case rcvd_confirm:
                          {
                            p_rcb->conv_state = Rcv;
                            goto ex0;
                          }
                       case rcvd_confirm_send:
                          {
                              p_rcb->conv_state = SEND;
                              goto ex0;
                          }
                       case rcvd_confirm_deall:
                          {
                           p_rcb->conv_state = END_CONV;
                           goto ex0;
                          }
                    }
        case Deallocate_flush:
        case Deallocate_confirm:
        case Deallocate_defer:
                    {
                        if((p_rcb->conv_state == RESET)||
                           (p_rcb->conv_state==SEND)||
                           (p_rcb->conv_state == pend_deall)) {
                           if(p_rcb->conv_state == SEND) {
                               if (p2==Deallocate_flush) {
                                 p_rcb->conv_state = RESET;
                               }
                               if (p2==Deallocate_confirm)
                                 p_rcb->conv_state = pend_deall;
                               if (p2==Deallocate_defer)
                                 p_rcb->conv_state = Deallocate_defer;
                                goto ex0;
                           }
                             else
                                    {
                                        goto ex_1;
                                    }
                        }
                           else
                                  {
                                       p_tcb = p_rcb -> p_tcb;
                                       goto ex1; }
                                  }
        case Deallocate_abend:
                       {
                        if((p_rcb->conv_state == RESET)||
                           (p_rcb->conv_state==END_CONV)||
                           (p_rcb->conv_state == pend_deall)) {
                           if(p_rcb->conv_state == END_CONV) {
                               p_tcb = p_rcb -> p_tcb;
                               goto ex1;
                           }
                             else
                                    {
                                        goto ex_1;
                                     }
                        }
                            else
                            {
                                p_rcb->conv_state = RESET;
                                goto ex0;
                            }
                       }
        case Deallocate_local:
                       {
                        if((p_rcb->conv_state == RESET)||
                           (p_rcb->conv_state==END_CONV)||
                           (p_rcb->conv_state == pend_deall)) {
                           if(p_rcb->conv_state == END_CONV) {
                            p_rcb->conv_state = RESET;
                            goto ex0;
                           }
                              else {
                                      goto ex_1;
                                   }
                           }
                           else
                                   {
                                     p_tcb = p_rcb -> p_tcb;
                                     goto ex1;
                                   }
                       }
        case Get_attributes:
                       {
                        if((p_rcb->conv_state == RESET)||
                           (p_rcb->conv_state == pend_deall)) {
                            goto ex_1;
                        }
                           else
                                {
                                    goto ex0;
                                }
                       }
      }
   }
 ex0: return(0);
 ex1:
      dcp(p_tcb);
      return(1);
 ex_1: return(-1);
}
