/*
 *	*********************
 * 	*  K E R M I T . C  *
 *	*********************
 *
 * Kermit-P/OS main program.  More later.
 *
 * By:
 *	Robert B. Denny
 *	10-Jan-84
 *
 * Edits:
 *
 * 12-Jan-84 RBD	Add server command GET.
 * 13-Jan-83 RBD	Add server FINISH & LOGOUT.  Rework KERFIL spawning
 *			so shares common code.
 * 14-Jan-84 RBD	Add permanent storage of setup values.
 *		
 */

/*
 * Undefine the following when MNU and HLP file
 * are assigned by the application installation
 * file.  Eventually, we'll get logicals implemented
 * in the C library for P/OS!!!
 */
#define TESTING

#include <rmstdio.h>
#include <cx.h>
#include <qiofun.h>
#include <qiottd.h>

#define IDENT "Y1.1.C"

ident IDENT;

int $$narg = 1;

/*
 * Kermit variable parameters & defaults
 */
static word baud = 1200;			/* Current baud rate */
static word stripfs = TRUE;			/* TRUE to strip filespecs */

/*
 * The following definitions MUST correspond to the 
 * option numbers in the format menu!! (HACK!!)
 */
#define NP8 1					/* 1 = 8 bit none */
#define EP7 2					/* 2 = 7-bit even */
#define OP7 3					/* 3 = 7-bit odd  */
static word format = NP8;			/* Data format */

/*
 * The following definitions MUST correspond to the 
 * option numbers in the format menu!! (HACK!!)
 */
#define TYPE1 1
#define TYPE2 2
#define TYPE3 3
static word blkchk = TYPE1;			/* Block check (1,2 or 3) */

/*
 * The following definitions MUST correspond to the 
 * option numbers in the format menu!! (HACK!!)
 */
#define ASCMODE 1
#define IMAGE   2
#define QMAGE   3
static word xmode = ASCMODE;			/* Transfer mode */

/*
 * Permanent storage of setup data
 */
#define SETUP_FILE "LB:[ZZSYS]KERSETUP.DAT"
static FILE *setdat;

/*
 * Menu data
 */
static int stat[8];				/* Used everywhere */
static char action[8];
static int  main_fl = FALSE;
static char *msg1 = "";
static char *msg2 = "";

static char *clrseq = "\033[1;1H\033[J";
static char *failed = "Operation failed";
static char *complete = "Operation complete";
static char *wrgkey = "You pressed the wrong function key";
static char *unsup = "Option not working yet";
static char m1buf[80];

extern int $dsw;

/*
 *	******************
 *	*  MAIN ROUTINE  *
 *	******************
 */
main()
   {

#ifdef TESTING      
   /*
    * The following 2 POSRES calls may be eliminated when the 
    * program is run via an application installation file.
    */
   if(p$mfile("KERMIT.MNU", stat) != 1)
      my_err("Failed to open KERMIT.MNU");
   if(p$hfile("KERMIT.HLP", "KERMAIN", stat) != 1)
      my_err("Failed to open KERMIT.HLP");
#endif   

   /*
    * Open the setup data file & read old values in.  If open fails,
    * create new one.
    */
   if((setdat = fopen(SETUP_FILE, "r")) == NULL)
      {
      if((setdat = fopen(SETUP_FILE, "w")) == NULL)
         {
         sprintf(m1buf, "Failed to create %s.  RMS code = %d\n",
            SETUP_FILE, $$ferr);
         p$fatler(m1buf);
         }
      else
         fprintf(setdat, "%d,%d,%d,%d,%d\n", baud, stripfs, format, 
            blkchk, xmode);
      }
   else
      {
      fgets(m1buf, 32, setdat);
      sscanf(m1buf, "%d,%d,%d,%d,%d", &baud, &stripfs, 
         &format, &blkchk, &xmode);
      }
   fclose(setdat);

   /*
    * Main loop
    */
   while(TRUE)
      {
      main_fl = FALSE;
      display("KERMAIN");
      switch(stat[0])
         {
         case 1:	/* DO key */
            switch(stat[1])		/*** HACK -- use action string!! ***/
               {
               case 1:
                  msg1 = do_kfi('s'); ; break;
               case 2:
                  msg1 = do_kfi('r'); ; break;
               case 3:
                  msg1 = do_kfi('g'); ; break;
               case 4:
                  msg1 = connect(); break;
               case 5:
                  msg1 = do_kfi('e'); ; break;
               case 6:
                  msg1 = do_kfi('q'); ; break;
               case 7:
                  msg1 = show(); break;
               case 8:
                  msg1 = set(); break;
               case 9:
                  msg1 = view(); break;
               case 10:
                  msg1 = files(); break;
               default:
                  msg1 = unsup;
               }
            break;
         
         case -14:	/* Function key */
            switch(stat[1])
               {
               case 10:                 /* Exit */
               case 9:                  /* Main Screen */
                  printf("%s", clrseq); fflush(stdout);
                  p$hclose(stat);
                  p$mclose(stat);
                  exits(1);
               
               default:
                  msg1 = wrgkey;
          
               }
            break;
         
         default:
            my_error("MENU error");
         }
      }
   }


/*
 *	*********************
 *	*  ACTION ROUTINES  *
 *	*********************
 */

/*
 * DO_KFI - Kick off KERFIL for specified operation
 *
 * FINISH takes you to CONNECT, LOGOUT takes you to VIEW.
 */
do_kfi(code)
char code;
   {
   char cmdlin[40];
   char buf[10];

   sprintf(cmdlin, "kfi %c%sb %d", code, fmtopt(buf), baud);
   if(code == 'q' || spawnit("KFI   ", cmdlin) != EX$SUC)
      return(view());
   else if(code == 'e')
      return(connect());
   else
      return(complete);
   }


/*
 * CONNECT - terminal emulation (use PRO/Comm for now)
 *
 * NOTE: DTE returns funny status.
 */
connect()
   {
#ifdef REALTHING
   if(spawnit("DTE   ", NULL) != EX$SUC)
      return(failed);
   else
      return(complete);
#else
   spawnit("DTE   ", NULL);
   return("");
#endif
   }

/*
 * SHOW - Show parameters
 */
static char *bc_dec[] = 
   {
   "Single character checksum",
   "Two character checksum",
   "Three character CRC-CCITT"
   };
static char *df_dec[] = 
   {
   "8 bits, no parity",
   "7 bits, even parity",
   "7 bits, odd parity"
   };
static char *ft_dec[] = 
   {
   "ASCII (text files)",
   "Image (8-bit data format)",
   "Image (7-bit with 8th bit quoting)"
   };

show()
   {

   printf("%s\033#6Kermit-P/OS Version %s:\n", clrseq, IDENT);
   printf("Block-check type:                 %s\n", bc_dec[blkchk-1]);
   printf("Receive startup delay:            30 sec.\n");
   printf("File transfer mode:               %s\n", ft_dec[xmode-1]);
   printf("IBM mode                          Not supported\n");
   printf("Incomplete file disposition       Deaccess locked\n");
   printf("Link protocol:\n");
   printf("   Line used                      XK0: (Comm port)\n");
   printf("   Local echo                     Not supported\n");
   printf("   Data rate (baud rate)          %d bits/sec.\n", baud);
   printf("   Data format                    %s\n", df_dec[format-1]);
   printf("Packet protocol:\n");
   printf("   Packet length                  94 bytes\n");
   printf("   Padding length                 0\n");
   printf("   Pad character                  NUL  (00 hex)\n");
   printf("   Timeout                        10 sec.\n");
   printf("   Retry maximum                  10 retries\n");
   printf("   End-of-line character          CR   (0D hex)\n");
   printf("   Control quoting character      '#'  (23 hex)\n");
   printf("   8th-bit quoting character      Not supported\n");
   printf("   Run-length encoding char.      Not supported\n");
   printf("   Start of packet character      SOH  (01 hex)\n\n");
   printf("Press RESUME to continue ..."); fflush(stdout);
   wtres();
   return("");
   }

/*
 * SET - Set communication parameters
 */
set()
   {
   msg1 = "";
   while(TRUE)
      {
      display("KERSET");
      switch(stat[0])
         {
         case 1:				/* DO key */
            switch(stat[1])
               {
               case 1:
                  msg1 = s_speed(); updset(); break;
               case 3:
                  msg1 = s_xfer(); updset(); break;
               case 5:
                  msg1 = s_fspec(); updset(); break;
               default:
                  msg1 = unsup;
               }
            break;

         case -14:
            switch(stat[1])
               {
               case 9:				/* Main screen */
                  main_fl = TRUE;
               case 10:
                  return("");
               default:
                  msg1 = wrgkey;
               }
             break;

         default:
             my_err("MENU error");
         }
      if(main_fl) return(msg1);			/* Lower level MAIN screen */
      }
   }

/*
 * S_SPEED - Set data rate
 */
s_speed()
   {
   msg1 = "";
   while(TRUE)
      {
      display("KERSPEED");
      switch(stat[0])
         {
         case 1:				/* DO key */
            switch(stat[1])
               {
               case 1:
                  baud = 300; break;
               case 2:
                  baud = 1200; break;
               case 3:
                  baud = 2400; break;
               case 4:
                  baud = 4800; break;
               case 5:
                  baud = 9600; break;
               case 6:
                  baud = 19200; break;
               default:
                  msg1 = "Speed selection error";
                  continue; 
               }
            sprintf(m1buf, "Data rate is now %d bits/sec.\n", baud);
            return(m1buf);

         case -14:
            switch(stat[1])
               {
               case 9:				/* Main screen */
                  main_fl = TRUE;
               case 10:
                  return("No change to data rate");
               default:
                  msg1 = wrgkey;
               }
            break;

         default:
             my_err("MENU error");
         }
      }
   }


/*
 * S_XFER - Set data format
 */
s_xfer()
   {
   msg1 = "";
   while(TRUE)
      {
      display("KERXFR");
      switch(stat[0])
         {
         case 1:				/* DO key */
            switch(stat[1])
               {
               case 1:
                  xmode = ASCMODE;
                  return("File type is ASCII");
               case 2:
                  xmode = IMAGE;
                  return("File type is IMAGE (8-bit)");
               default:
                  return(unsup);
               }
           break;

         case -14:
            switch(stat[1])
               {
               case 9:				/* Main screen */
                  main_fl = TRUE;
               case 10:
                  return("No change to file type");
               default:
                  msg1 = wrgkey;
               }
             break;

         default:
             my_err("MENU error");
         }
      }
   }

/*
 * S_FSPEC - Set file spec handling
 */
s_fspec()
   {
   msg1 = "";
   while(TRUE)
      {
      display("KERFSPEC");
      switch(stat[0])
         {
         case 1:				/* DO key */
            switch(stat[1])
               {
               case 1:
                  stripfs = TRUE;
                  return("Short file specifications");
               case 2:
                  stripfs = FALSE;
                  return("Full P/OS file specifications");
               default:
                  return(unsup);
               }
           break;

         case -14:
            switch(stat[1])
               {
               case 9:				/* Main screen */
                  main_fl = TRUE;
               case 10:
                  return("No change to file spec handling");
               default:
                  msg1 = wrgkey;
               }
            break;

         default:
             my_err("MENU error");
         }
      }
   }

/*
 * VIEW - Switch to message/status display
 */
view()
   {
   spawnit("C$VUTL", NULL);
   return("");
   }

/*
 * FILES - Switch to file services
 */
files()
   {
   spawnit("C$FUTL", NULL);
   return("");
   }


/*
 *	*********************
 * 	*  LOCAL FUNCTIONS  *
 *	*********************
 */

/*
 * DISPLAY - Load and display selected menu
 */
display(frame)
char *frame;
   {
   if(p$mframe(frame, action, sizeof(action), stat) != 1)
      my_err("MFRAME error");
   p$menu(action, sizeof(action), FALSE, msg1, msg2, stat);
   }

/*
 * FMTOPT - Format command line options for KERFIL & KERDTE
 */
fmtopt(buf)
char *buf;
   {
   register char *cp;

   cp = buf;
   if(xmode != ASCMODE)
      *cp++ = 'i';
   if(!stripfs)
      *cp++ = 'f';
   *cp++ = '\0';
   return(buf);
   }

/*
 * MY_ERROR - Fatal application errors
 */
my_error(str)
char *str;
   {
   sprintf(m1buf, "%s  status = [%d, %d]", str, stat[0], stat[1]);
   p$fatler(m1buf);
   }

/*
 * SPAWNIT - Switch to offspring task
 */
#define SPWN_EFN 16

spawnit(task, cmd)
char *task;
char *cmd;
   {
   rad50 tname[2];
   int cmdlen;
   char buf[80];

   printf(clrseq); fflush(stdout);

   if(cmd == 0 || (cmdlen = strlen(cmd)) == 0)
      cmd = 0;
   ascr50(strlen(task), task, tname);
   qiow(IO_DET, 1, 1, 0, 0, 0);		/* Detach terminal */
   if(spwn(tname, 0, SPWN_EFN, 0, stat, cmd, cmdlen) != IS_SUC)
      {
      sprintf(buf, "Spawn of task \"%s\" failed.  Code = %d\n", task, $dsw);
      p$fatler(buf);
      }
   stse(SPWN_EFN);
   qiow(IO_ATT|TF_ESQ, 1, 1, 0, 0, 0);	/* Re-attach terminal (???) */
   return(stat[0]);
   }

/*
 * updset - Update the setup file
 */
updset()
   {
   if((setdat = fopen(SETUP_FILE, "a")) == NULL)
      {
      sprintf(m1buf, "Failed to open %s for update.  RMS code = %d\n",
         SETUP_FILE, $$ferr);
      p$fatler(m1buf);
      }
   fseek(setdat, 0l, 0);
   fprintf(setdat, "%d,%d,%d,%d,%d\n", baud, stripfs, format, blkchk, xmode);
   fclose(setdat);
   }
