home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / uclkermit.zip / cuclker.c < prev    next >
C/C++ Source or Header  |  1988-08-16  |  66KB  |  1,599 lines

  1. /* File uclk15.c on ucl u44d   -   UCL Kermit main source file;
  2.                     Chris Kennington.       30th September 1985         */
  3.  
  4.  
  5. /*  This is a remote-only Kermit for Berkeley Unix 2.8 (11/44),
  6.           produced at UCL by surgery on the "demonstration" Kermit,
  7.           plus enhancements.
  8.     The program should run unmodified in any unix-like environment;
  9.           for use in any other environment in which an ASCII OS supports
  10.           a VDU terminal on an RS232 port, there should be no need to
  11.           modify any routines in this file.  All possibly machine-dependent
  12.           routines have been isolated in file "uclkmd.c"; these should
  13.           be checked before compilation.
  14.     8th-bit prefixing is specified by a "8" flag on the command-line;
  15.           "7" forces 7-bit, "i" forces 8-bit image.  If no such flag, then
  16.           7-bit is assumed.  Repeat-prefixing is always potentially on.
  17.     In 7-bit mode only: LF is converted to CR/LF in transmission
  18.           and CR, LF, CR/LF or LF/CR to LF on receipt; this code is
  19.           in the machine-dependent routines.
  20.              Chris Kennington.       UCL.    9th May 1985.        */
  21.  
  22. /*  The modification history of this program is in file uclkmods.dox    */
  23.  
  24.  
  25.  
  26. /* Identification string:                                       */
  27. char  ident[] ="UCL Remote-only Kermit,  V15B,  March 1986.\n";
  28.  
  29.  
  30. #include <stdio.h>          /* Standard UNIX definitions */
  31. #include <ctype.h>          /* isascii definitions       */
  32.  
  33.  
  34. /* MAX & MIN values accepted                            */
  35. #define MAXPACKSIZ  94      /* Maximum packet size */
  36. #define MAXTIM      60      /* Maximum timeout interval */
  37. #define MAXTRY      10      /* Times to retry a packet */
  38. #define MINTIM      2       /* Minumum timeout interval */
  39.  
  40. /* My values to send to other end                       */
  41. #define MYEOL       '\n'    /* End-Of-Line character I need */
  42. #define MYPAD       0       /* Number of padding characters I will need */
  43. #define MYPCHAR     0       /* Padding character I need (NULL) */
  44. #define MYQUOTE     '#'     /* Quote character I will use */
  45. #define MYTIME      10      /* Seconds after which I should be timed out */
  46.  
  47. /* Boolean constants                                    */
  48. #define TRUE        -1
  49. #define FALSE       0
  50.  
  51. /* ASCII Chars                                          */
  52. #define LF          10
  53. #define CR          13      /* ASCII Carriage Return */
  54. #define DEL         127     /* Delete (rubout) */
  55. #define ESC         0x1b    /* real escape char        */
  56. #define SOH         1       /* Start of header */
  57. #define SP          32      /* ASCII space */
  58.  
  59. /* Macro Definitions */
  60.  
  61. /*
  62.  * tochar: converts a control character to a printable one by adding a space.
  63.  * unchar: undoes tochar.
  64.  * ctl:    converts between control characters and printable characters by
  65.  *         toggling the control bit (ie. ^A becomes A and A becomes ^A).
  66.  */
  67. #define tochar(ch)  ((ch) + ' ')
  68. #define unchar(ch)  ((ch) - ' ')
  69. #define ctl(ch)     ((ch) ^ 64 )
  70.  
  71. #define forever     while(1)
  72.  
  73. /* procedures passed as arguments etc.:-                                */
  74. extern  char cread();
  75. extern  char rinit(), rfile(), rdata();     /* receive procedures       */
  76. extern  char sinit(), sfile(), sdata(), seof(), sbreak(); /* send procs */
  77. extern  int  outfc(), outfile();
  78.  
  79. /* procedures in system-dependent file uclkmd.c:-                       */
  80. extern  char   ascout(), ascedit(), filerr(), nextin();
  81. extern  int    flushinput(), cooktty(), rawtty(), timoset(), unbuffer();
  82.  
  83.  
  84.  
  85. /* Global Variables */
  86.  
  87. int
  88.           aflg, rflg, sflg,   /* flags for AUTO, RECEIVE, SEND */
  89.           debug,              /* indicates level of debugging output (0=none) */
  90.           filnamcnv,          /* -1 means do file name case conversions */
  91.           filecount,          /* Number of files left to send */
  92.           image, oimage,      /* 0 = 7-bit, 1 = 8-bit mode, 2 = prefixing */
  93.           n,                  /* Packet number */
  94.           oldt,               /* previous char in encode()        */
  95.           numtry,             /* Times this packet retried */
  96.           oldtry,             /* Times previous packet retried */
  97.           pad,                /* How much padding to send */
  98.           qu8,
  99.           rpt,
  100.           rptflg,
  101.           sz,
  102.           size,               /* Size of present data */
  103.           spsiz,              /* Maximum send packet size */
  104.           timint = 10;        /* Timeout for foreign host on sends */
  105.  
  106. char
  107.           c,                  /* dummy char               */
  108.           *dname,             /* name of debug file UCL   */
  109.           *dt,                /* data-block code/decode   */
  110.           eol = '\n',         /* End-Of-Line character to send */
  111.           **filelist,         /* List of files to be sent */
  112.           *filenames[11],
  113.           *filnam,            /* Current file name */
  114.           getfiles[MAXPACKSIZ],
  115.           iflg = 0,           /* 8th-bit-mode set */
  116.           packet[MAXPACKSIZ], /* Packet buffer */
  117.           padchar,            /* Padding character to send */
  118.           quote = '#',        /* Quote character in incoming data */
  119.           recpkt[MAXPACKSIZ], /* Receive packet buffer */
  120.           state,              /* Present state of the automaton */
  121.           timflag,            /* timeout flag UCL         */
  122.           type;               /* received-packet type     */
  123.  
  124. char  amauto[]   = "%sI am in automatic-server mode!";
  125. char  badpack[]  = "%sYour Kermit sent invalid packet, type \"%c\"!";
  126. char  crlf[]     = "\r\n";
  127. char  *eighths[] = {"7-bit character", "binary-image-mode", "8th-bit prefixed"};
  128. char  goodbye[]  = "%sReturning to Unix; goodbye.";
  129. char  *logicval[]= {"OFF", "ON"};
  130. char  noname[]   = "%sNo valid names in GET request";
  131. char  null[]     = "";       /* null string              */
  132. char  onlyg[]    = "%sOnly BYE, LOGOUT, FINISH commands implemented";
  133. char  prompt[]   = "KmUCL: ";
  134.  
  135. FILE    *fp,                /* current disk file */
  136.           *dfp;               /* debug file UCL           */
  137.  
  138.  
  139.  
  140. /*
  141.  *  m a i n
  142.  *  Main routine - parse command and options, set up the
  143.  *  tty lines, and dispatch to the appropriate routine.
  144.  */
  145.  
  146. main(argc,argv)
  147. int argc;                           /* Character pointers to and count of */
  148. char **argv;                            /* command line arguments */
  149. {
  150.     char *cp, **argv1;
  151.     static char first = 0;
  152.     int  argc1;
  153.  
  154.     if (first != 0) {
  155.           printmsg("Program fault - reentered.\n");
  156.           exit(1);
  157.     }
  158.     else
  159.           ++first;
  160.     unbuffer();                         /* unbuffer output */
  161.     printf(ident);
  162.     aflg = sflg = rflg = 0;             /* Turn off all parse flags */
  163.     cp = *++argv;
  164.     argv1 = argv;                       /* remember argument pointers */
  165.     argv++;
  166.     argc1 = --argc;
  167.     --argc;                             /* pointers to args */
  168. /*  Initialize these values and hope the first packet will get across OK */
  169.     eol = CR;                           /* EOL for outgoing packets */
  170.     quote = '#';                        /* Standard control-quote char "#" */
  171.     pad = 0;                            /* No padding */
  172.     padchar = NULL;                     /* Use null if any padding wanted */
  173.     spsiz = MAXPACKSIZ;
  174.     qu8 = 0;
  175.     image = -1;
  176.     rptflg = TRUE;                      /* try for repeating    */
  177.     filnamcnv = TRUE;                   /* conversion for UNIX systems */
  178.  
  179.     dfp = 0;
  180.     dname = 0;                          /* clear debug file ptrs        */
  181.  
  182.     if (argc >= 0) while ((*cp) != NULL) switch (*cp++) {
  183.   /* If command-line, parse characters in first arg.            */
  184.  
  185.               case 'a':
  186.                     aflg++;  break;         /* A = Auto command     */
  187.  
  188.               case 'f':
  189.                     filnamcnv = FALSE;      /* F = don't do case conversion */
  190.                     break;                  /*     on filenames */
  191.  
  192.               case 'h':
  193.                     debug = 0;              /* there won't be a file yet */
  194.                     help();                 /* H = help messages    */
  195.  
  196.               case 'i':                   /* I = Image (8-bit) mode */
  197.                     image = 1;
  198.                     ++iflg;
  199.                     break;
  200.  
  201.               case 'r':
  202.                     rflg++; break;          /* R = Receive command */
  203.  
  204.               case 's':
  205.                     sflg++;  break;         /* S = Send command */
  206.  
  207.               case '7':                   /* 7-bit transfer               */
  208.                     image = 0;
  209.                     ++iflg;
  210.                     break;
  211.  
  212.               case '8':                   /* 8-bit prefixed               */
  213.                     image = 2;
  214.                     ++iflg;
  215.                     break;
  216.  
  217.               case '-':                   /* - flag (ignored)             */
  218.                     break;
  219.  
  220.               default:
  221.                     --cp;
  222.                     printmsg("Invalid char %c in command-line.",*cp);
  223.                     usage();
  224.           }
  225.     if (image == -1)
  226.           image = 0;              /* default is 7-bit             */
  227.     oimage = image;             /* remember setting             */
  228.  
  229. /* Flags parsed, check for debug filename                       */
  230.     cp = *argv;
  231.     if (*cp == '-') {
  232.           if (*++cp != 'D') {     /* invalid debug filename       */
  233.               printmsg("Debug filename <%s> must start with \"D\".",*--cp);
  234.               usage();
  235.           }
  236.           while (*cp == 'D') {    /* count the Ds                 */
  237.               ++debug;
  238.               ++cp;
  239.           }
  240.           dname = cp;             /* filename starts after Ds     */
  241.           dfp = fopen(dname,"a");
  242.           ++argv;
  243.           --argc;
  244.     }
  245.  
  246.     if ((c = aflg+sflg+rflg) > 1) {         /* Only one command allowed */
  247.           printmsg("One only of Auto OR Receive OR Send!");
  248.           usage();
  249.     }
  250.     if (iflg > 1) {
  251.           printmsg("One only of \"i\" or \"7\" !");
  252.           usage();
  253.     }
  254.     printmsg("%s transfer requested;",eighths[image]);
  255.     if (image != 0)
  256.           printf("        CR <=> LF translation will NOT be done.\n");
  257.  
  258.     if (c == 0) {               /* no action-flag       */
  259.           printf(crlf);
  260.           printmsg("No action on command-line; Automatic mode assumed;\n  For help use \"kermit  h\".");
  261.           aflg = 1;
  262.     }
  263.  
  264. /* Put the tty into the correct mode */
  265.     rawtty();
  266.  
  267. /* All set up, now execute the command that was given. */
  268.  
  269.     if (debug) {
  270.           if (dfp != 0) {
  271.               printmsg("Debugging level = %d into file \"%s\";",debug,dname);
  272.               fprintf(dfp,"\n\n******** UCL Kermit Debug File ** next run starts here  **********\n");
  273.               fprintf(dfp,ident);
  274.               fprintf(dfp,"\nDebugging level = %d into file \"%s\";\nCommand-line: <",debug,dname);
  275.               while (argc1-- > 0)
  276.                     fprintf(dfp,"  %s",*argv1++);
  277.               fprintf(dfp,"  >;");
  278.               if (aflg) fprintf(dfp,"\nAuto Command\n");
  279.               if (sflg) fprintf(dfp,"\nSend Command\n");
  280.               if (rflg) fprintf(dfp,"\nReceive Command\n");
  281.           }
  282.           else {
  283.               printf("No valid debug file, debug switched off.\r\n");
  284.               debug = 0;
  285.           }
  286.     }
  287.  
  288.     if (sflg)                           /* Send command */
  289.     {
  290.           if (argc--) {
  291.               printmsg("Send Command; set your Kermit to receive files\n");
  292.               filnam = *argv++;   /* Get file to send */
  293.           }
  294.           else {
  295.               cooktty();                  /* restore tty to normal  */
  296.               printmsg("Send, but no filename given;\n");
  297.               usage();                    /* and give error */
  298.           }
  299.           fp = NULL;                      /* Indicate no file open yet */
  300.           filelist = argv;                /* Set up the rest of the file list */
  301.           filecount = argc;               /* Number of files left to send */
  302.           printmsg("I'll give you 10 seconds to get ready ...");
  303.           timoset(10);
  304.           while (timflag != 0)
  305.               c = cread();                /* hang about           */
  306.           if (sendsw() == FALSE)          /* Send the file(s) */
  307.               printmsg("Send failed.");   /* Report failure */
  308.           else                            /*  or */
  309.               printmsg("done.");          /* success */
  310.     }
  311.  
  312.     else if (rflg) {                         /* Receive command */
  313.           printmsg("Receive Command; set your Kermit to Send files\n");
  314.           printmsg("I'll give you 5 seconds to get ready ...");
  315.           timoset(5);
  316.           while (timflag != 0)
  317.               c = cread();                /* hang about           */
  318.           timint = 20;
  319.           if (recsw() == FALSE)           /* Receive the file(s) */
  320.               printmsg("Receive failed.");
  321.           else                            /* Report failure */
  322.               printmsg("done.");          /* or success */
  323.     }
  324.  
  325.     else while (aflg) {         /* automatic (sub-server) mode  */
  326.           printmsg("Auto Command; set your Kermit to Send or Get files;");
  327. printf("\tto cancel, use \"LOGOUT\", \"BYE\" or \"FINISH\" command,\r\n");
  328.           printf("\t(or send ESCAPE-C at any time).\r\n");
  329.           if (autosw() ==  TRUE)
  330.               printmsg("Auto Send/Get complete");
  331.           else
  332.               printmsg("Auto-mode cancelled");
  333.     }
  334.     closeall();
  335.     cooktty();
  336.     exit(0);
  337. }                       /* End main()                   */
  338.  
  339.  
  340.  
  341. autosw()                /* state switcher for automatic mode     */
  342. {
  343.     int   len, num;
  344.     char  c, *wild;
  345.  
  346.     forever {
  347.           timint = 40;           /* slow NAKs at first           */
  348.           if (debug)
  349.               fprintf(dfp,"\nAutosw() waiting:  8th-bit setting now %d, char is %c; reptflag %s.\n",image,qu8,logicval[-rptflg]);
  350.           n = numtry = 0;
  351.           switch ( (type = rpack(&len,&num,recpkt)) ) {
  352.   /* decipher request from micro                                */
  353.  
  354.             case 'S':             /* send-init                    */
  355.   /* receive file(s) from local Kermit                          */
  356.               state = 'F';
  357.               rpar(recpkt,len);
  358.               len = spar(packet);
  359.               spack('Y',n,len,packet);     /* ack parameters   */
  360.               n = (n+1)%64;
  361.               while (state != 'C') {      /* until EoF            */
  362.                     if (debug == 1) fprintf(dfp," autosw state %c\n",state);
  363.                     switch(state) {
  364.                       case 'F':  state = rfile();  break;
  365.                       case 'D':  state = rdata();  break;
  366.                       case 'A':  state = 'C';  break;
  367.                       case 'C':  break;
  368.               }   }                       /* end switch, while    */
  369.               image = oimage;
  370.               break;                      /* end of reception     */
  371.  
  372.             case 'R':             /* get command                  */
  373.   /* send file(s) to micro Kermit                               */
  374. if (debug) fprintf(dfp,"\n  getting files <%s>, ", recpkt);
  375.               movemem(recpkt,getfiles,len); /* file name(s)       */
  376.               getfiles[len] = 0;
  377.               wild = getfiles;
  378.               while ( (c = (*wild++)&0x7f) != 0 )
  379.                     if ( (c == '*') || (c == '?') ) {
  380.                         error("Cannot accept wildcard <%c> in \"GET\"",c);
  381.                         break;      /* no wildcard processing       */
  382.                     }
  383.               filecount = decol8(getfiles,filenames,10);
  384.               filelist = filenames;
  385. if (debug > 1) {
  386.     fprintf(dfp," %d files, ",filecount);
  387.     while (*filelist != 0)
  388.           fprintf(dfp,"<%s> ",*filelist++);
  389.     filelist = filenames;
  390. }
  391.               if (filecount--) {          /* if any valid names   */
  392.                     filnam = *filelist++;
  393.                     fp = NULL;
  394.                     if (sendsw() == FALSE)          /* Send the file(s) */
  395.                         printmsg("Send failed.");   /* Report failure */
  396.                     else
  397.                         printmsg("Files sent; still in auto-mode.");
  398.               }
  399.               else                        /* if no names          */
  400.                     error(noname,prompt);
  401.               image = oimage;
  402.               break;
  403.  
  404.             case 'G':             /* generic command              */
  405.   /* only "BYE" and "LOGOUT" are acceptable                     */
  406.               if ( ( (c = *recpkt&0x5f) == 'F' ) || (c == 'L') ) {
  407.                     error(goodbye,prompt);
  408.                     aflg = 0;
  409.                     return(TRUE);
  410.               }
  411.               else
  412.                     error(onlyg,prompt);
  413.               break;
  414.  
  415.             case 'I':             /* info-exchange packet         */
  416.               rpar(recpkt,len);
  417.               len = spar(packet);
  418.               spack('Y',n,len,packet);      /* ack the parameters   */
  419.               break;
  420.  
  421.             case 'E':             /* error packet                 */
  422.               prerrpkt(recpkt);
  423.               aflg = 0;
  424.               error(goodbye,prompt);
  425.               return(FALSE);
  426.  
  427.             case 'C':             /* OS command                   */
  428.               error(onlyg,prompt);
  429.               break;
  430.  
  431.             case 'N':             /* NAK - out of phase           */
  432.               error(amauto,prompt);
  433.               break;
  434.  
  435.             case FALSE:           /* timeout - micro not sending  */
  436.               printf(crlf);
  437.               printmsg("Please enter \"SEND\", \"GET\" or \"BYE\" command to micro Kermit,");
  438.               printf("\t(or send ESCAPE-C to cancel UCL Kermit) ...\n");
  439.               spack('N',0,0,null);
  440.               break;
  441.  
  442.             default:              /* bad packet                   */
  443.               error(badpack,prompt,type);
  444.               return(FALSE);
  445.  
  446.     }   }               /* end switch, forever                  */
  447. }               /* End autosw()                                 */
  448.  
  449.  
  450.  
  451. bufill(buffer)
  452. /*  Get a bufferful of data from the file that's being sent     */
  453. char *buffer;
  454. {
  455.     int t;
  456.     static  int  softeof= FALSE;
  457.  
  458.     if (softeof == TRUE) {
  459.           softeof = FALSE;
  460.           return(EOF);
  461.     }
  462.     rpt = sz = 0;                       /* Inits for encode()   */
  463.     dt = buffer;
  464.     oldt = -2;                          /* impossible last char */
  465.     while((t = getc(fp)) != EOF) {      /* next character       */
  466.           t = ascedit(t);                 /*  edited if necessary */
  467.           encode(t);                      /*   to buffer          */
  468.           if (sz >= spsiz-6)              /* Check length         */
  469.                return(sz);
  470.     }
  471.   /* reach here on (hard) EOF or error                          */
  472.     if (sz==0)
  473.        return(EOF);
  474.     else {
  475.           softeof = TRUE;                 /* EOF next time        */
  476.           return(sz);
  477.     }
  478. }                       /* end of bufill()                      */
  479.  
  480.  
  481. closeall()              /* close both files             */
  482. {
  483.     if (fp != NULL)
  484.           fclose(fp);
  485.     if (dfp != NULL) {
  486.           fprintf(dfp,"\n\n************************* End of Run ******************************\n\n");
  487.           fclose(dfp);
  488.     }
  489. }                       /* end of closeall()            */
  490.  
  491.  
  492.  
  493. char  cread()           /* get next char from line      */
  494. /*  UCL Input Routine: handle escapes as well,
  495.           return SOH & printables, eat all other controls. */
  496. {
  497.     char  c, t;
  498.     int   ex;
  499.  
  500.     ex =  0;
  501.     while (ex == 0) {
  502.           t = nextin();           /* get next char        */
  503.           if (timflag == 0)
  504.               return(0);          /* timeout occured      */
  505.           c = t&0x7f;
  506.           if (image != 1)
  507.               t = c;
  508.           if ( (c == CR) || (c == LF) || (c == SOH) || (c > 0x1f) )
  509.               return(t);
  510. /* left only with invalid controls */
  511.           if (c == ESC) {         /* process escape       */
  512.               printf("\nKmUCL-ESC");
  513. Repeat:                         /* for ignoring "-"     */
  514.               read (0, &t, 1);
  515.               putchar(t);
  516.               c = t&0x5f;
  517.               switch(c) {
  518.                 case  SOH:
  519.                     return(t);
  520.                 case  'C':
  521.                     cooktty();
  522.                     printf("\nUCL Kermit exitting by ESC-C from local station\n");
  523.                     closeall();
  524.                     exit(1);
  525.                 case 'H':
  526.                     printf("\n\rUCL Kermit is alive and well ....\n\r");
  527.                     break;
  528.                 case 0x1f:                /* ?            */
  529.                 case 0x0f:                /* /            */
  530.                     cooktty();
  531.                     help1();
  532.                     rawtty();
  533.                     break;
  534.                 case '-':
  535.                     goto Repeat;
  536.                 default:
  537.                     printf("???");
  538.                     break;
  539.     }   }   }
  540.     return(0);
  541. }                       /* End of cread()               */
  542.  
  543.  
  544.  
  545.  
  546. decode(buf,len)              /* packet decoding procedure    */
  547. /* Called with string to be decoded; Returns 0 or error-code. */
  548. char *buf;
  549. int  len;
  550. {
  551.     char  a, a7, b8, *end, rep;
  552.     int   flg8=0, error=0, r;
  553.  
  554.     if (image == 2)
  555.           flg8 = -1;
  556.  
  557.     end = buf + len;
  558.     while (buf < end) {
  559.           a = *buf++;
  560.           if ( rptflg && (a == '~') ) {   /* got a repeat prefix? */
  561.                     rep = unchar(*buf++);   /* Yes, get the repeat count, */
  562.                     a = *buf++;             /* and get the prefixed character. */
  563.           }
  564.           else
  565.               rep = 1;
  566.           b8 = 0;                         /* Check high order "8th" bit */
  567.           if ( flg8 && (a == qu8) ) {
  568.                     b8 = 0200;
  569.                     a = *buf++;             /* and get the prefixed character. */
  570.               }
  571.           if (a == quote) {               /* If control prefix, */
  572.               a  = *buf++;                /* get its operand. */
  573.               a7 = a & 0177;              /* Only look at low 7 bits. */
  574.               if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */
  575.               a = ctl(a);                 /* if in control range. */
  576.           }
  577.           a |= b8;                        /* OR in the 8th bit */
  578.  
  579.           while (rep-- > 0) {
  580.               if (image == 0)            /*  if 7-bit            */
  581.                     r = ascout(a);
  582.               else                        /*  prefixing / image   */
  583.                     r = putc(a,fp);
  584.               if (r == EOF)               /* if error             */
  585.                     error |= filerr();
  586.     }   }
  587.     return(error);
  588. }                       /* end of decode()                      */
  589.  
  590.  
  591.  
  592. decol8(line,arr,num)      /* decollate command-line       */
  593. /* Splits up line into sections delimited by controls or blanks,
  594.      zeros all such chars & places start-addresses into array,
  595.      up to maximum of num entries; zeros rest of entries and
  596.      returns count of valid entries.                    */
  597. char  *line, *arr[], num;
  598. {
  599.     char  c, count, *start;
  600.     int   i, j;
  601.  
  602.     j = count = 0;
  603.     start = line;
  604.     for (i=0; i<80, j<num; ++i) {
  605.           if ( (c = line[i]) <= SP) {     /* terminator   */
  606.               line[i] = 0;
  607.               if (count > 0) {
  608.                     arr[j++] = start;
  609.                     count = 0;
  610.               }
  611.               if (c == 0)
  612.                     break;          /* out of for           */
  613.           }
  614.           else if (count++ == 0)  /* printable            */
  615.               start = &line[i];   /* start next parm      */
  616.     }                           /* end else, for        */
  617.     line[i] = 0;                /* terminate last parm  */
  618.     i = j;                      /* number of parms      */
  619.     while (j < num)
  620.           arr[j++] = 0;           /* clear garbage        */
  621.     return(i);
  622. }                       /* End of decol8()              */
  623.  
  624.  
  625.  
  626. encode(a)
  627. /* encode single character into packet for transmission */
  628. int a;                          /* char to be encoded           */
  629. {
  630.     int a7;                             /* Low order 7 bits     */
  631.     int b8;                             /* 8th bit of character */
  632.     int flg8 = 0;
  633.     static  int  oldsz;
  634.  
  635.     if (image == 2)
  636.           flg8 = -1;
  637.  
  638.     if (rptflg) {               /* repeat-count processing      */
  639.           if (a == oldt) {                /* char is same         */
  640. /* This algorithm is simple but relatively inefficient; it stores
  641.           the repeat flag, count and character each time around so
  642.           that when the run is broken the buffer is valid; also it
  643.           treats a pair as a run, which requires 3 bytes not 2 unless
  644.           the pair is control- or 8bit-prefixed; but it does not
  645.           require lookahead logic from the data-read.             */
  646.               sz = oldsz;                 /* wind back pointer    */
  647.               dt[sz++] = '~';             /*  store prefix        */
  648.               dt[sz++] = tochar(++rpt);   /*   & count            */
  649.               if (rpt > 93)               /* force new start      */
  650.                     oldt = -2;              /* impossible value     */
  651.           }
  652.           else {                          /* not run, or end      */
  653.               rpt = 1;
  654.               oldt = a;                   /* save char            */
  655.               oldsz = sz;
  656.     }   }
  657.  
  658.     a7 = a & 0177;                      /* Isolate ASCII part */
  659.     b8 = a & 0200;                      /* and 8th (parity) bit. */
  660.  
  661.     if (flg8 && b8) {                   /* Do 8th bit prefix if necessary. */
  662.           dt[sz++] = qu8;
  663.           a = a7;
  664.     }
  665.     if ((a7 < SP) || (a7==DEL)) {      /* Do control prefix if necessary */
  666.           dt[sz++] = MYQUOTE;
  667.           a = ctl(a);
  668.     }
  669.     if (a7 == MYQUOTE)                  /* Prefix the control prefix */
  670.           dt[sz++] = MYQUOTE;
  671.     else if (rptflg && (a7 == '~'))     /* If it's the repeat prefix, */
  672.           dt[sz++] = MYQUOTE;             /* quote it if doing repeat counts. */
  673.     else if (flg8 && (a7 == qu8))               /* Prefix the 8th bit prefix */
  674.           dt[sz++] = MYQUOTE;             /* if doing 8th-bit prefixes */
  675.  
  676.     dt[sz++] = a;                       /* Finally, insert the character */
  677.     dt[sz] = '\0';                      /* itself, and mark the end. */
  678.     return;
  679. }                       /* end of encode()              */
  680.  
  681.  
  682.  
  683. /*VARARGS1*/
  684. error(fmt, a1, a2, a3, a4, a5)
  685. /*  Remote; send an error packet with the message.
  686.  *    and if debug log in debug file                    */
  687. char *fmt;
  688. {
  689.     char msg[100];
  690.     int len;
  691.  
  692.     sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
  693.     len = strlen(msg);
  694.     spack('E',n,len,msg);           /* Send the error packet */
  695.     if (debug) fprintf(dfp,msg);
  696.     return;
  697. }                       /* End of error()               */
  698.  
  699.  
  700.  
  701. gnxtfl()                /*  Get next file in a file group       */
  702. {
  703.     if (debug) fprintf(dfp,"\n   gnxtfl: filelist = \"%s\"",*filelist);
  704.     filnam = *(filelist++);
  705.     if (filecount-- == 0)
  706.           return FALSE; /* If no more, fail */
  707.     else
  708.           return TRUE;                   /* else succeed */
  709. }                       /* End gnxtfl()                 */
  710.  
  711.  
  712.  
  713.  
  714. help()                  /* UCL help routine             */
  715. {
  716.     printf("\nSummary of UCL Remote Kermit:\n");
  717.     help1();
  718.     printf("\t\t\t\t hit CR for more ");
  719.     timoset(30);
  720.     while (timflag != 0)
  721.           if (cread() != 0)
  722.               break;
  723.     printf("\nBasic syntax of the \"kermit\" command is:\n");
  724.     usage();                    /* exits                */
  725. }                       /* End of help()                */
  726.  
  727.  
  728.  
  729. help1()
  730. {
  731.     printf("\nThis is a remote receive-or-send-or-auto Kermit; normally called\n");
  732.     printf("  with a system command-line, failing which it enters automatic mode.\n");
  733.     printf("Image-mode transfers may be selected by \"i\"-flag, 8-bit-prefixed transfers\n");
  734.     printf("  by \"8\"-flag, otherwise 7-bit data only will be transferred;\n");
  735.     printf("  mapping between LFs and CR/LF pairs is only done during 7-bit transfers.\n");
  736.     printf("Repeat-prefixing is always available; there is NO Connect facility.\n");
  737.     printf("Automatic mode supports the Server-Kermit commands \"SEND\", \"GET\"\n");
  738.     printf("  and \"LOGOUT/BYE/QUIT\".\n");
  739.     printf("If your transfer breaks down, go into connect-mode and enter\n");
  740.     printf("  ESCAPE-C, which will cause UCL Kermit to quit gracefully;\n");
  741.     printf("  alternatively enter ESCAPE-H, which will elicit a reassurance.\n");
  742.     printf("If debug is requested by \"-D\" flag(s) on second parameter, then\n");
  743.     printf("  debug information is written into a file whose name is \n");
  744.     printf("  the rest of the second parameter (after last \"D\"); up to three\n");
  745.     printf("  \"D\" flags may be entered (but only one \"-\"):\n");
  746.     printf("Debug = 1 gives basic trace of automaton states + error-messages,\n");
  747.     printf("      = 2 logs packets as sent/received,\n");
  748.     printf("      = 3 also logs all chars as read from line, in hex.\n");
  749.     return;
  750. }                               /* End of help1()                       */
  751.  
  752.  
  753.  
  754. movemem(from,to,count)          /* shift block of data                  */
  755. /* moves chars starting at bottom of block                              */
  756. char    *from, *to;
  757. int     count;
  758. {
  759.     while (count-- > 0)
  760.           *to++ = *from++;
  761.     return;
  762. }                               /* End of movemem()                     */
  763.  
  764.  
  765.  
  766. prerrpkt(msg)  /* Print contents of error packet received from remote host. */
  767. char *msg;
  768. {
  769.     if (debug) {
  770.           fprintf(dfp,"\nKmUCL Aborting with following message from local Kermit:");
  771.           msg[50] = 0;
  772.           fprintf(dfp,"\n  \"%s\"",msg);
  773.     }
  774.     return;
  775. }                       /* End prerrpkt()               */
  776.  
  777.  
  778.  
  779.  
  780. /*VARARGS1*/
  781. printmsg(fmt, a1, a2, a3, a4, a5)
  782. /*  Print message on standard output ;
  783.  *       message will only be received if remote is in connect-mode. */
  784. char *fmt;
  785. {
  786.           printf("KmUCL: ");
  787.           printf(fmt,a1,a2,a3,a4,a5);
  788.           printf("\n\r");
  789.           return;
  790. }                       /* End of printmsg()                    */
  791.  
  792.  
  793.  
  794.  
  795. char rdata()            /*  Receive Data                */
  796. {
  797.     int num, len;                       /* Packet number, length */
  798.  
  799.     if (debug > 2)    printf(" ** rdata() ");
  800.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  801.  
  802.     switch(rpack(&len,&num,packet))     /* Get packet */
  803.     {
  804.           case 'D':                       /* Got Data packet */
  805.               if (num != n)               /* Right packet? */
  806.               {                           /* No */
  807.                     if (oldtry++ > MAXTRY)
  808.                         return('A');        /* If too many tries, abort */
  809.                     if (num == ((n==0) ? 63:n-1)) { /* duplicate?   */
  810.                         spack('Y',num,0,null); /* Yes, re-ACK it    */
  811.                         numtry = 0;         /* Reset try counter    */
  812.                         return(state);      /* Don't write out data! */
  813.                     }
  814.                     else return('A');       /* sorry, wrong number */
  815.               }
  816.               /* Got data with right packet number */
  817.               if ( (num = decode(packet,len)) != 0 ) {
  818.                     error("Trouble writing file, OS code %xx",num);
  819.                     return('A');
  820.               }
  821.               spack('Y',n,0,null);           /* Acknowledge the packet */
  822.               n = (n+1)%64;               /* Bump packet number, mod 64 */
  823.               oldtry = numtry;            /* Reset the try counters */
  824.               numtry = 0;                 /* ... */
  825.               return('D');                /* Remain in data state */
  826.  
  827.           case 'F':                       /* Got a File Header */
  828.               if (oldtry++ > MAXTRY)
  829.                     return('A');            /* If too many tries, "abort" */
  830.               if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  831.               {                           /* It was the previous one */
  832.                     spack('Y',num,0,null);     /* ACK it again */
  833.                     numtry = 0;             /* Reset try counter */
  834.                     return(state);          /* Stay in Data state */
  835.               }
  836.               else return('A');           /* Not previous packet, "abort" */
  837.  
  838.           case 'Z':                       /* End-Of-File */
  839.               if (num != n) return('A');  /* Must have right packet number */
  840.               spack('Y',n,0,null);           /* OK, ACK it. */
  841.               fclose(fp);                 /* Close the file */
  842.               fp = NULL;
  843.               if (debug) {
  844.                     if ( (len != 0) && (*packet == 'D') )
  845.                         fprintf(dfp,"\nFile <%s> truncated by local Kermit\n",filnam);
  846.                     else
  847.                         fprintf(dfp,"\nFile <%s> received OK\m",filnam);
  848.               }
  849.               if ( (len != 0) && (*packet == 'D') && (image != 1) )
  850.                     fprintf(fp,"\n\n*** Local Kermit Truncated this File <%s> ***\n", filnam);
  851.               n = (n+1)%64;               /* Bump packet number */
  852.               return('F');                /* Go back to Receive File state */
  853.  
  854.           case 'E':                       /* Error packet received */
  855.               prerrpkt(packet);           /* Print it out and */
  856.               return('A');                /* abort */
  857.  
  858.           case FALSE:                     /* Didn't get packet */
  859.               spack('N',n,0,null);           /* Return a NAK */
  860.               return(state);              /* Keep trying */
  861.  
  862.           default:
  863.               error(badpack,prompt,type);
  864.               return('A');       /* Some other packet, "abort" */
  865.     }
  866. }                       /* End of rdata()               */
  867.  
  868.  
  869.  
  870.  
  871. recsw()         /* state table switcher for receiving files.    */
  872. {
  873.     if (debug) fprintf(dfp,"Ready to receive file\n");
  874.     if (debug > 2)    printf(" ** recsw() ");
  875.     state = 'R';                        /* Receive-Init is the start state */
  876.     n = 0;                              /* Initialize message number */
  877.     numtry = 0;                         /* Say no tries yet */
  878.  
  879.     forever {
  880.           if (debug == 1) fprintf(dfp," recsw state: %c\n",state);
  881.           switch(state)                   /* Do until done */
  882.           {
  883.               case 'R':   state = rinit(); break; /* Receive-Init */
  884.               case 'F':   state = rfile(); break; /* Receive-File */
  885.               case 'D':   state = rdata(); break; /* Receive-Data */
  886.               case 'C':   return(TRUE);           /* Complete state */
  887.               case 'A':   return(FALSE);          /* "Abort" state */
  888.           }
  889.     }
  890. }                       /* End recsw()                          */
  891.  
  892.  
  893.  
  894. char rfile()            /*  Receive File Header                 */
  895. {
  896.     int num, len;                       /* Packet number, length */
  897.     char filnam1[50];                   /* Holds the converted file name */
  898.  
  899.     if (debug > 2)    printf(" ** rfile() ");
  900.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  901.  
  902.     switch(rpack(&len,&num,packet))     /* Get a packet */
  903.     {
  904.           case 'S':                       /* Send-Init, maybe our ACK lost */
  905.               if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  906.               if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */
  907.                     len = spar(packet);           /* our Send-Init parameters */
  908.                     spack('Y',num,len,packet);
  909.                     numtry = 0;             /* Reset try counter */
  910.                     return(state);          /* Stay in this state */
  911.               }
  912.               else return('A');           /* Not previous packet, "abort" */
  913.  
  914.           case 'Z':                       /* End-Of-File */
  915.               if (oldtry++ > MAXTRY) return('A');
  916.               if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  917.               {                           /* Yes, ACK it again. */
  918.                     spack('Y',num,0,null);
  919.                     numtry = 0;
  920.                     return(state);          /* Stay in this state */
  921.               }
  922.               else return('A');           /* Not previous packet, "abort" */
  923.  
  924.           case 'F':                       /* File Header (just what we want) */
  925.               if (num != n) return('A');  /* The packet number must be right */
  926.               packet[49] = 0;             /* ensure string closed */
  927.               strcpy(filnam1, packet);    /* Copy the file name */
  928.  
  929.               if (filnamcnv) {            /* Convert upper case to lower */
  930.                     for (filnam=filnam1; *filnam != '\0'; filnam++)
  931.                         if (*filnam >= 'A' && *filnam <= 'Z')
  932.                               *filnam |= 040;
  933.                     filnam = filnam1;
  934.               }
  935.  
  936.               if (debug) fprintf(dfp,"\nOpening <%s> for receiving.",filnam1);
  937.               if ((fp=fopen(filnam1,"w")) == NULL) {
  938.                     error("%sCannot create <%s>",prompt,filnam1);
  939.                     return('A');
  940.               }
  941.               else                        /* OK, give message */
  942.                     if (debug) fprintf(dfp,"\nReceiving %s as %s",packet,filnam1);
  943.  
  944.               spack('Y',n,0,null);           /* Acknowledge the file header */
  945.               oldtry = numtry;            /* Reset try counters */
  946.               numtry = 0;                 /* ... */
  947.               n = (n+1)%64;               /* Bump packet number, mod 64 */
  948.               return('D');                /* Switch to Data state */
  949.  
  950.           case 'B':                       /* Break transmission (EOT) */
  951.               if (num != n) return ('A'); /* Need right packet number here */
  952.               spack('Y',n,0,null);           /* Say OK */
  953.               if (debug) fprintf(dfp,"All files received\n");
  954.               return('C');                /* Go to complete state */
  955.  
  956.           case 'E':                       /* Error packet received */
  957.               prerrpkt(packet);           /* Print it out and */
  958.               return('A');                /* abort */
  959.  
  960.           case FALSE:                     /* Didn't get packet */
  961.               spack('N',n,0,null);           /* Return a NAK */
  962.               return(state);              /* Keep trying */
  963.  
  964.           default:
  965.               error(badpack,prompt,type);
  966.               return ('A');       /* Some other packet, "abort" */
  967.     }
  968. }                       /* End rfile()                  */
  969.  
  970.  
  971.  
  972. char rinit()            /*  Receive Initialization              */
  973. {
  974.     int len, num;                       /* Packet length, number */
  975.  
  976.     if (debug > 2)    printf(" ** rinit() ");
  977.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  978.  
  979.     switch(rpack(&len,&num,packet))     /* Get a packet */
  980.     {
  981.           case 'S':                       /* Send-Init */
  982.               rpar(packet,len);
  983.               len = spar(packet);
  984.               spack('Y',n,len,packet);      /* ACK with my parameters */
  985.               oldtry = numtry;            /* Save old try count */
  986.               numtry = 0;                 /* Start a new counter */
  987.               n = (n+1)%64;               /* Bump packet number, mod 64 */
  988.               return('F');                /* Enter File-Receive state */
  989.  
  990.           case 'E':                       /* Error packet received */
  991.               prerrpkt(packet);           /* Print it out and */
  992.               return('A');                /* abort */
  993.  
  994.           case 'I':                       /* Init-parameters      */
  995.               rpar(packet,len);
  996.               len = spar(packet);
  997.               spack('Y',n,len,packet); /* ack with our parameters */
  998.               n = (n+1)%64;               /* Bump packet number, mod 64 */
  999.               return(state);              /*  & continue          */
  1000.  
  1001.           case FALSE:                     /* Didn't get packet */
  1002.               spack('N',n,0,null);           /* Return a NAK */
  1003.               return(state);              /* Keep trying */
  1004.  
  1005.           default:
  1006.               error(badpack,prompt,type);
  1007.               return('A');       /* Some other packet type, "abort" */
  1008.     }
  1009. }                       /* End rinit()                          */
  1010.  
  1011.  
  1012.  
  1013.  
  1014. rpack(len,num,data)     /*  Read a Packet                       */
  1015. int *len, *num;                         /* Packet length, number */
  1016. char *data;                             /* Packet data */
  1017. {
  1018.     int i, done;                        /* Data character number, loop exit */
  1019.     char t,                             /* Current input character */
  1020.           cchksum,                        /* Our (computed) checksum */
  1021.           rchksum;                        /* Checksum received from other host */
  1022.  
  1023.     if (debug > 2)    printf(" ** rpack() ");
  1024.     timoset(timint);         /* set timeout                     */
  1025. /* The way timeouts are handled is that the flag stays clear, indicating
  1026.           that a timeout has occurred, until it is set to a value again
  1027.           by the next call to timoset().  This means that the effect can
  1028.           run up thro' the procedures without using longjmp().    */
  1029.  
  1030.     t = 0;
  1031.     *len = 0;                           /* in case times out    */
  1032.     while (t != SOH) {                  /* Wait for packet header */
  1033.           t = cread() & (char)0x7f;
  1034.           if (timflag == 0)
  1035.               return(FALSE);
  1036.     }
  1037.  
  1038.     done = FALSE;                       /* Got SOH, init loop */
  1039.     while (!done)                       /* Loop to get a packet */
  1040.     {
  1041.           t = cread();               /* Get character */
  1042.           if (timflag == 0)
  1043.               return(FALSE);
  1044.           if (t == SOH) continue;         /* Resynchronize if SOH */
  1045.           cchksum = t;                    /* Start the checksum */
  1046.           *len = unchar(t)-3;             /* Character count */
  1047.  
  1048.           t = cread();               /* Get character */
  1049.           if (timflag == 0)
  1050.               return(FALSE);
  1051.           if (t == SOH) continue;         /* Resynchronize if SOH */
  1052.           cchksum = cchksum + t;          /* Update checksum */
  1053.           *num = unchar(t);               /* Packet number */
  1054.  
  1055.           t = cread();               /* Get character */
  1056.           if (timflag == 0)
  1057.               return(FALSE);
  1058.           if (t == SOH) continue;         /* Resynchronize if SOH */
  1059.           cchksum = cchksum + t;          /* Update checksum */
  1060.           type = t;                       /* Packet type */
  1061.  
  1062.           for (i=0; i<*len; i++) {         /* The data itself, if any */
  1063.               t = cread();           /* Get character */
  1064.               if (timflag == 0)
  1065.                     return(FALSE);          /* as tho' bad checksum */
  1066.               if (t == SOH)
  1067.                     break;                  /* Resynch if SOH */
  1068.               cchksum = cchksum + t;      /* Update checksum */
  1069.               data[i] = t;                /* Put it in the data buffer */
  1070.           }
  1071.           if (t == SOH)
  1072.               continue;
  1073.           data[*len] = 0;                 /* Mark the end of the data */
  1074.  
  1075.           t = cread();               /* Get last character (checksum) */
  1076.           if (timflag == 0)
  1077.               return(FALSE);
  1078.           rchksum = unchar(t);            /* Convert to numeric */
  1079.           if (t == SOH)                   /* Resynchronize if SOH */
  1080.               continue;
  1081.           done = TRUE;                    /* Got checksum, done */
  1082.     }
  1083.     timocan();
  1084.  
  1085.     if (debug) fprintf(dfp,"Packet %d received; ",*num);
  1086.     if (debug>1) {                       /* Display incoming packet */
  1087.           fprintf(dfp," type: %c;",type);
  1088.           fprintf(dfp," num:  %d;",*num);
  1089.           fprintf(dfp," len:  %d.",*len);
  1090.           if (*len != 0) {
  1091.               fprintf(dfp,"\n  data: <");
  1092.               for (i=0; i<*len; ++i)
  1093.                     putc(data[i],dfp);
  1094.               putc('>',dfp);
  1095.     }   }
  1096.                                                   /* Fold in bits 7,8 to compute */
  1097.     cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  1098.     if (cchksum != rchksum) {
  1099.           if (debug)
  1100.               fprintf(dfp,"\n bad checksum: rec'd %xx computed %xx; ",
  1101.                 rchksum, cchksum);
  1102.           return(FALSE);
  1103.     }
  1104.     flushinput();
  1105.  
  1106.     return(type);                       /* All OK, return packet type */
  1107. }                               /* End of rpack()                       */
  1108.  
  1109.  
  1110.  
  1111.  
  1112. rpar(data,len)  /* instal received parameters safely            */
  1113. char    *data, len;
  1114. /* Set up incoming parameters to either what has been received
  1115.           or, if nil, to defaults.
  1116.   No return-code.                                               */
  1117. {
  1118.     char        p;
  1119.  
  1120.   /* initialize to defaults in case incoming block is short     */
  1121.     spsiz = 80;                 /* packet-length 80 chars       */
  1122.     timint = MYTIME;          /* timeout as defined           */
  1123.     eol = CR;                   /* terminator normally CR       */
  1124.     quote = '#';                /* standard control-quote char  */
  1125.     rptflg = FALSE;             /*  nor repeat-quoting          */
  1126.  
  1127.     while (len-- > 0) {
  1128.           p = data[len];
  1129.  
  1130.           switch (len) {          /* for each parameter           */
  1131.  
  1132.             case 0:                       /* MAXL                 */
  1133.               spsiz = unchar(p);
  1134.               break;
  1135.  
  1136.             case 1:                       /* TIME                 */
  1137.               timint = (unchar(p) < 5) ? 5 : unchar(p);
  1138.               break;
  1139.  
  1140.             case 2:                       /* NPAD                 */
  1141.               pad = unchar(p);
  1142.               break;
  1143.  
  1144.             case 3:                       /* PADC                 */
  1145.               padchar = ctl(p);
  1146.               break;
  1147.  
  1148.             case 4:                       /* EOL                  */
  1149.               eol = unchar(p);
  1150.               break;
  1151.  
  1152.             case 5:                       /* QCTL                 */
  1153.               quote = p;
  1154.               break;
  1155.  
  1156.             case 6:                       /* QBIN                 */
  1157.               if (image == 2) {
  1158.                     if (p == 'Y')
  1159.                         qu8 = '&';
  1160.                     else if (isalnum(p) == 0) /* provided punctuation */
  1161.                         qu8 = p;
  1162.                     else
  1163.                         image = 0;
  1164.                     break;
  1165.               }
  1166.               break;
  1167.  
  1168.             case 8:                       /* REPT                 */
  1169.               if (p == '~')
  1170.                     rptflg = TRUE;
  1171.               break;
  1172.  
  1173.             default:                      /* CHKT, CAPAS etc.     */
  1174.               break;
  1175.  
  1176.     }   }                       /* end while & outer switch     */
  1177.  
  1178.     if ( (qu8 == 0) && (image == 2) )   /* invlaid setting      */
  1179.           image = 0;
  1180.     if (debug)
  1181.           fprintf(dfp,"\nParameters in:  8th-bit setting now %d, char is %c; reptflag %s.",image,qu8,logicval[-rptflg]);
  1182.     return;
  1183. }                       /* End of rpar()                        */
  1184.  
  1185.  
  1186.  
  1187.  
  1188. char sbreak()           /* send EoT (break)                     */
  1189. {
  1190.     int num, len;                       /* Packet number, length */
  1191.     if (debug > 2)    printf(" ** sbreak() ");
  1192.     if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  1193.  
  1194.     spack('B',n,0,packet);              /* Send a B packet */
  1195.     switch (rpack(&len,&num,recpkt))    /* What was the reply? */
  1196.     {
  1197.           case 'N':                       /* NAK, just stay in this state, */
  1198.               num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
  1199.               if (n != num)               /* which is just like an ACK for */
  1200.                     return(state);          /* this packet so fall thru to... */
  1201.  
  1202.           case 'Y':                       /* ACK */
  1203.               if (n != num) return(state); /* If wrong ACK, fail */
  1204.               numtry = 0;                 /* Reset try counter */
  1205.               n = (n+1)%64;               /* and bump packet count */
  1206.               return('C');                /* Switch state to Complete */
  1207.  
  1208.           case 'E':                       /* Error packet received */
  1209.               prerrpkt(recpkt);           /* Print it out and */
  1210.               return('A');                /* abort */
  1211.  
  1212.           case FALSE: return('C');        /* Receive failure, count as OK */
  1213. /* If timed out or etc. when completing, likely other end has gone away */
  1214.  
  1215.           default:
  1216.               error(badpack,prompt,type);
  1217.               return ('A');       /* Other, "abort" */
  1218.    }
  1219. }                       /* End sbreak()                         */
  1220.  
  1221.  
  1222.  
  1223.  
  1224. char sdata()            /* send data packet                      */
  1225. {
  1226.     int num, len;                       /* Packet number, length */
  1227.  
  1228.     if (debug > 2)    printf(" ** sdata() ");
  1229.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  1230.  
  1231.     spack('D',n,size,packet);           /* Send a D packet */
  1232.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  1233.     {
  1234.           case 'N':                       /* NAK, just stay in this state, */
  1235.               num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  1236.               if (n != num)               /* which is just like an ACK for */
  1237.                     return(state);          /* this packet so fall thru to... */
  1238.  
  1239.           case 'Y':                       /* ACK */
  1240.               if (n != num) return(state); /* If wrong ACK, persist */
  1241.               numtry = 0;                 /* Reset try counter    */
  1242.               n = (n+1)%64;               /* Bump packet count    */
  1243.               if (len != 0) switch (*recpkt) {   /* ACK has data */
  1244.                 case 'Z':                         /* cancel all   */
  1245.                 case 'z':
  1246.                     filecount = 0;                 /* no more to go */
  1247.                 case 'X':                         /* cancel file  */
  1248.                 case 'x':
  1249.                     return('Z');
  1250.                 default:                          /* invalid      */
  1251.                     recpkt[20] = 0;                 /*  truncate    */
  1252.                     error("%sLocal Kermit sent ACK with data: <%s> - goodbye!",prompt,recpkt);
  1253.                     return('A');
  1254.               }
  1255.               if ((size = bufill(packet)) != EOF) /* data from file */
  1256.                     return('D');            /* Got data, stay in state D */
  1257.   /* EOF can mean either really end-of-file or an error         */
  1258.               if ( (num = filerr()) != 0 ) {    /* actual error */
  1259.                     error("Problem while reading file, OS code %xx",num);
  1260.                     return('A');
  1261.               }
  1262.               return('Z');                /* EOF                  */
  1263.  
  1264.  
  1265.           case 'E':                       /* Error packet received */
  1266.               prerrpkt(recpkt);           /* Print it out and */
  1267.               return('A');                /* abort */
  1268.  
  1269.           case FALSE: return(state);      /* Receive failure, stay in D */
  1270.  
  1271.           default:
  1272.               error(badpack,prompt,type);
  1273.               return('A');        /* Anything else, "abort" */
  1274.     }
  1275. }                       /* End sdata()                          */
  1276.  
  1277.  
  1278.  
  1279.  
  1280. sendsw()
  1281. /*  Sendsw is the state table switcher for sending files.  It loops until
  1282.  *  either it finishes, or an error is encountered.  The routines called
  1283.  *  by sendsw are responsible for changing the state.           */
  1284. {
  1285.     if (debug) {
  1286.           fprintf(dfp,"\nSendsw() sending file; ");
  1287.           if (debug > 2)
  1288.                     printf(" ** sendsw() ");
  1289.     }
  1290.     state = 'S';                        /* Send initiate is the start state */
  1291.     n = 0;                              /* Initialize message number */
  1292.     numtry = 0;                         /* Say no tries yet */
  1293.     forever {                           /* Do this as long as necessary */
  1294.           if (debug == 1) fprintf(dfp," sendsw state: %c\n",state);
  1295.           switch(state) {
  1296.               case 'S':   state = sinit();  break; /* Send-Init */
  1297.               case 'F':   state = sfile();  break; /* Send-File */
  1298.               case 'D':   state = sdata();  break; /* Send-Data */
  1299.               case 'Z':   state = seof();   break; /* Send-End-of-File */
  1300.               case 'B':   state = sbreak(); break; /* Send-Break */
  1301.               case 'C':   return (TRUE);           /* Complete */
  1302.               case 'A':   return (FALSE);          /* "Abort" */
  1303.               default:    return (FALSE);          /* Unknown, fail */
  1304.           }
  1305.     }
  1306. }                       /* End sendsw()                         */
  1307.  
  1308.  
  1309.  
  1310.  
  1311. char seof()             /*  Send EoF                               */
  1312. {
  1313.     int num, len;                       /* Packet number, length */
  1314.     if (debug > 2)    printf(" ** seof() ");
  1315.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  1316.  
  1317.     spack('Z',n,0,packet);              /* Send a 'Z' packet */
  1318.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  1319.     {
  1320.           case 'N':                       /* NAK, just stay in this state, */
  1321.               num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
  1322.               if (n != num)               /* which is just like an ACK for */
  1323.                     return(state);          /* this packet so fall thru to... */
  1324.  
  1325.           case 'Y':                       /* ACK */
  1326.               if (n != num) return(state); /* If wrong ACK, hold out */
  1327.               numtry = 0;                 /* Reset try counter */
  1328.               n = (n+1)%64;               /* and bump packet count */
  1329.               if (debug) fprintf(dfp,"\nClosing input file <%s>, ",filnam);
  1330.               fclose(fp);                 /* Close the input file */
  1331.               fp = NULL;                  /* Set flag indicating no file open */
  1332.  
  1333.               if (debug) fprintf(dfp,"looking for next file...");
  1334.               if (gnxtfl() == FALSE) {     /* No more files go? */
  1335.                     if (debug) fprintf(dfp,"\nNo more files to send.");
  1336.                     return('B');            /* if not, break, EOT, all done */
  1337.               }
  1338.               if (debug) fprintf(dfp,"New file is %s\n",filnam);
  1339.               return('F');                /* More files, switch state to F */
  1340.  
  1341.           case 'E':                       /* Error packet received */
  1342.               prerrpkt(recpkt);           /* Print it out and */
  1343.               return('A');                /* abort */
  1344.  
  1345.           case FALSE: return(state);      /* Receive failure, stay in Z */
  1346.  
  1347.           default:
  1348.               error(badpack,prompt,type);
  1349.               return('A');        /* Something else, "abort" */
  1350.     }
  1351. }                       /* End seof()                           */
  1352.  
  1353.  
  1354.  
  1355.  
  1356. char sfile()            /* send file header                     */
  1357. {
  1358.     int num, len;                       /* Packet number, length */
  1359.     char filnam1[50],                   /* Converted file name */
  1360.           *newfilnam,                     /* Pointer to file name to send */
  1361.           *cp;                            /* char pointer */
  1362.  
  1363.     if (debug > 2)    printf(" ** sfile() ");
  1364.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  1365.  
  1366.     if (fp == NULL) {                   /* If not already open, */
  1367.           if (debug) fprintf(dfp,"\nOpening %s for sending.",filnam);
  1368.           fp = fopen(filnam,"r");         /* open the file to be sent */
  1369.           if (fp == NULL)                 /* If bad file pointer, give up */
  1370.           {
  1371.               error("%sCannot open file <%s>",prompt,filnam);
  1372.               return('A');
  1373.           }
  1374.     }
  1375.  
  1376.     strcpy(filnam1, filnam);            /* Copy file name */
  1377.     newfilnam = cp = filnam1;
  1378.     while (*cp != '\0')                 /* Strip off all leading directory */
  1379.           if (*cp++ == '/')               /* names (ie. up to the last /). */
  1380.               newfilnam = cp;
  1381.  
  1382.     if (filnamcnv)                      /* Convert lower case to upper  */
  1383.           for (cp = newfilnam; *cp != '\0'; cp++)
  1384.               if (*cp >= 'a' && *cp <= 'z')
  1385.                     *cp ^= 040;
  1386.  
  1387.     len = cp - newfilnam;               /* Compute length of new filename */
  1388.  
  1389.     if (debug) fprintf(dfp,"\nSending %s as %s",filnam,newfilnam);
  1390.  
  1391.     spack('F',n,len,newfilnam);         /* Send an F packet */
  1392.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  1393.     {
  1394.           case 'N':                       /* NAK, just stay in this state, */
  1395.               num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  1396.           case 'Y':                       /* ACK */
  1397.               if (n != num)
  1398.                     return(state);          /* If wrong ACK, stay in F state */
  1399.               numtry = 0;                 /* Reset try counter */
  1400.               n = (n+1)%64;               /* Bump packet count */
  1401.  
  1402.               if ((size = bufill(packet)) != EOF) /* data from file */
  1403.                     return('D');            /* Got data, stay in state D */
  1404.   /* EOF can mean either really end-of-file or an error         */
  1405.               if ( (num = filerr()) != 0 ) {    /* actual error */
  1406.                     error("Problem while reading file, OS code %xx",num);
  1407.                     return('A');
  1408.               }
  1409.               return('Z');                /* EOF (empty file)     */
  1410.  
  1411.           case 'E':                       /* Error packet received */
  1412.               prerrpkt(recpkt);           /* Print it out and */
  1413.               return('A');                /* abort */
  1414.  
  1415.           case FALSE: return(state);      /* Receive failure, stay in F state */
  1416.  
  1417.           default:
  1418.               error(badpack,prompt,type);
  1419.               return('A');        /* Something else, just "abort" */
  1420.     }
  1421. }                       /* End sfile()                  */
  1422.  
  1423.  
  1424.  
  1425.  
  1426. char sinit()            /* send initiate (exchange parameters)  */
  1427. {
  1428.     int num, len;                       /* Packet number, length */
  1429.  
  1430.     if (debug > 2)    printf(" ** sinit() ");
  1431.     flushinput();                       /* Flush pending input */
  1432.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  1433.     len = spar(packet);                 /* Fill up init info packet */
  1434.     spack('S',n,len,packet);              /* Send an S packet */
  1435.  
  1436.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  1437.     {
  1438.           case 'N':
  1439.               num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  1440.               if (n != num)               /* which is just like an ACK for */
  1441.                     return(state);          /* this packet so fall thru to... */
  1442.  
  1443.           case 'Y':                       /* ACK */
  1444.               if (n != num)               /* If wrong ACK, stay in S state */
  1445.                     return(state);          /* and try again */
  1446.               rpar(recpkt,len);           /* Get other side's init info */
  1447.               numtry = 0;                 /* Reset try counter */
  1448.               n = (n+1)%64;               /* Bump packet count */
  1449.               return('F');                /* OK, switch state to F */
  1450.  
  1451.           case 'E':                       /* Error packet received */
  1452.               prerrpkt(recpkt);           /* Print it out and */
  1453.               return('A');                /* abort */
  1454.  
  1455.           case 'I':                       /* Init-parameters      */
  1456.               rpar(packet,len);
  1457.               len = spar(packet);
  1458.               spack('Y',n,len,packet); /* ack with our parameters */
  1459.               n = (n+1)%64;               /* Bump packet number, mod 64 */
  1460.               return(state);              /*  & continue          */
  1461.  
  1462.           case FALSE: return(state);      /* Receive failure, try again */
  1463.  
  1464.           default:
  1465.               error(badpack,prompt,type);
  1466.               return('A');           /* Anything else, just "abort" */
  1467.     }
  1468. }                       /* End sinit()                          */
  1469.  
  1470.  
  1471.  
  1472. spack(stype,num,len,data)        /*  Send a Packet               */
  1473. char stype, *data;
  1474. int num, len;
  1475. {
  1476.     int i;                              /* Character loop counter */
  1477.     char chksum, buffer[100];           /* Checksum, packet buffer */
  1478.     register char *bufp;                /* Buffer pointer */
  1479.  
  1480.     if (debug > 1) {                     /* Display outgoing packet */
  1481.           fprintf(dfp,"\nSending packet;  type: %c;",stype);
  1482.           fprintf(dfp," num: %d;",num);
  1483.           fprintf(dfp," len:  %d;",len);
  1484.           if (len != 0) {
  1485.               fprintf(dfp,"\n  data: <");
  1486.               for (i=0; i<len; ++i)
  1487.                     putc(data[i],dfp);
  1488.               putc('>',dfp);
  1489.     }   }
  1490.  
  1491.     bufp = buffer;                      /* Set up buffer pointer */
  1492.     for (i=1; i<=pad; i++) write(0,&padchar,1); /* Issue any padding */
  1493.  
  1494.     *bufp++ = SOH;                      /* Packet marker, ASCII 1 (SOH) */
  1495.     *bufp++ = tochar(len+3);            /* Send the character count */
  1496.     chksum  = tochar(len+3);            /* Initialize the checksum */
  1497.     *bufp++ = tochar(num);              /* Packet number */
  1498.     chksum += tochar(num);              /* Update checksum */
  1499.     *bufp++ = stype;                     /* Packet type */
  1500.     chksum += stype;                     /* Update checksum */
  1501.  
  1502.     for (i=0; i<len; i++)               /* Loop for all data characters */
  1503.     {
  1504.           *bufp++ = data[i];              /* Get a character */
  1505.           chksum += data[i];              /* Update checksum */
  1506.     }
  1507.     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  1508.     *bufp++ = tochar(chksum);           /* Put it in the packet */
  1509.     *bufp++ = eol;                      /* Extra-packet line terminator */
  1510.     *bufp = CR;                         /* CR for network       */
  1511.     write(0, buffer,bufp-buffer+1);     /* Send the packet */
  1512.     if (debug) {
  1513.           fprintf(dfp," Packet %d sent;\n",num);
  1514.           if (debug > 2)
  1515.               printf("\n\r");
  1516.     }
  1517.     return;
  1518. }                       /* End of spack()                       */
  1519.  
  1520.  
  1521.  
  1522.  
  1523. spar(data)              /* fill up packet with own parameters   */
  1524. char    *data;
  1525. /* returns length of parameter block (6, 7 or 9)                */
  1526. {
  1527.     char        len;
  1528.  
  1529.     data[0] = tochar(spsiz);
  1530.     data[1] = tochar(MYTIME);
  1531.     data[2] = tochar(MYPAD);
  1532.     data[3] = ctl(0);
  1533.     data[4] = tochar(MYEOL);
  1534.     data[5] = MYQUOTE;
  1535.     len = 6;
  1536.     if (image == 2) {                   /* 8th-bit prefixing    */
  1537.           if (qu8 == 0)
  1538.               data[6] = 'Y';
  1539.           else
  1540.               data[6] = qu8;              /*  feed back 8-quote   */
  1541.           len = 7;
  1542.     }
  1543.     else
  1544.           data[6] = 'N';
  1545.     if (rptflg) {               /* unless repeating turned off  */
  1546.           data[7] = '1';                  /*  1-byte checksum     */
  1547.           data[8] = '~';                  /*  only ~ for repeating*/
  1548.           len = 9;
  1549.     }
  1550.     if (debug)
  1551.           fprintf(dfp,"\nParameters out: 8th-bit setting now %d, char is %c; reptflag %s.",image,qu8,logicval[-rptflg]);
  1552.     return(len);
  1553. }                       /* End of spar()                        */
  1554.  
  1555.  
  1556.  
  1557.  
  1558. timocan()               /* cancel timeout               */
  1559. {
  1560.     timoset(0);
  1561.     timflag = 0xff;
  1562.     return;
  1563. }                       /* End of timocan()             */
  1564.  
  1565.  
  1566.  
  1567. timoex()                /* action timeout               */
  1568. {
  1569.     timflag = 0;                /* clear flag           */
  1570.     if (debug) {
  1571.           printmsg("Timeout ... ");
  1572.           fprintf(dfp,"Timeout ...");
  1573.     }
  1574.     return;
  1575. }                       /* End of timoex()              */
  1576.  
  1577.  
  1578.  
  1579. usage()         /*  Print summary of usage info and quit        */
  1580. {
  1581.     cooktty();
  1582.     printf("Usage: kermit  s[f78i] [-Ddebug-file] file(s) ... (send mode)\n");
  1583.     printf("or:    kermit  r[f78i] [-Ddebug-file]             (receive mode)\n");
  1584.     printf("or:    kermit  a[f78i] [-Ddebug-file]             (auto  mode)\n");
  1585.     printf("  where  f  =  filenames not converted to upper case,\n");
  1586.     printf("         7  =  force 7-bit data transfer,\n");
  1587.     printf("         8  =  attempt 8th-bit-prefixed transfer,\n");
  1588.     printf("         i  =  force 8-bit-image transfer,\n");
  1589.     printf("  and debug-file-name is preceded by \"-\" and up to 3 \"D\"-flags.\n");
  1590.     printf("or:    kermit  h                                  (help display).\n");
  1591.     printf(crlf);
  1592.     closeall();
  1593.     exit(0);
  1594. }                       /* End of usage()                       */
  1595.  
  1596.  
  1597.  
  1598. /**************  END of FILE  uclk??.c  **************************/
  1599.