home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / perkinelmeridris / pe7mai.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  21KB  |  723 lines

  1. /* pe7mai.c */
  2. /*
  3.  *    K e r m i t  File Transfer Utility
  4.  *
  5.  *    UNIX Kermit, Columbia University, 1981, 1982, 1983
  6.  *    Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
  7.  *
  8.  *    Also:   Jim Guyton, Rand Corporation
  9.  *        Walter Underwood, Ford Aerospace
  10.  *
  11.  * usage    kermit -s [-f -d -i -u -t -p -l -b] file ...    to send files
  12.  *            kermit -r [-d -i -u -t -p -l -b]            to receive files
  13.  *            kermit -g [-f -d -i -u -t -p -l -b] file ...    to get files
  14.  *            kermit -f [-d -t -p -l]                    to send finish command
  15.  *            kermit -x [-d -v -i -u -t -p -l]            to set server mode
  16.  *    where    s=send <flag>, r=receive <flag>, x=server <flag>,
  17.  *            f=finish mode <flag>, g=get files mode <flag>,
  18.  *            d=debug level <number>, v=verbose mode <flag>,
  19.  *            i= image mode <flag>, u=no file name conversion <flag>
  20.  *            l=tty line <device>, b=baud rate <speed>,
  21.  *            t=turnaround mode <flag>, p=parity type <char>
  22.  */
  23.  
  24. /*
  25.  *    Modification History:
  26.  *
  27.  *  Version 1.1(0)
  28.  *  December 4, 1986 - Add btobemp to decode other prefixxed packets.
  29.  *                   - Split program into parts to allow compiling on
  30.  *                     machine with minimum memory configuration.
  31.  *                     put in version number (use -v flag)
  32.  *                        Chris Lent (ihnp4!philabs!phri!cooper!chris)
  33.  *  March 85    - Change to use the IDRIS operating system
  34.  
  35.  *  Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
  36.  *      - Changed MYEOL character from \n to \r.
  37.  *      - Change char to int in bufill so getc would return -1 on
  38.  *        EOF instead of 255 (-1 truncated to 8 bits)
  39.  *      - Added read() in rpack to eat the EOL character
  40.  *      - Added fflush() call in printmsg to force the output
  41.  *      NOTE: The last three changes are not conditionally compiled
  42.  *        since they should work equally well on any system.
  43.  *
  44.  *      Changed Berkeley 4.x conditional compilation flag from
  45.  *      UNIX4X to UCB4X.
  46.  *      Added support for error packets and cleaned up the printing
  47.  *      routines.
  48.  */
  49. #define KVERSION "Perkin-Elmer 7000 Series 1.1(0) 5 Dec 86"
  50. #define UTEXT    0        /* Set for 8 bit text strings */
  51.  
  52. #include <std.h>        /* Standard UNIX definitions */
  53. #include <sys.h>        /* Idris system subroutines */
  54. /*#include "sgtty.h"        /* Special tty defs */
  55. #include "pe7tty.h"        /* Special tty defs */
  56.  
  57. /* Symbol Definitions */
  58.  
  59. #define BUFSIZE 80        /* A buffer size for I/O */
  60. #define MAXTRY    8        /* Times to retry a packet */
  61. #define SOH        1        /* Start of header */
  62. #define CR        13        /* ASCII Carriage Return */
  63. #define XON        17        /* ASCII xon character */
  64. #define SP        32        /* ASCII space */
  65. #define DEL        127        /* Delete (rubout) */
  66.  
  67. #define MAXPACKSIZ    94    /* Maximum packet size */
  68. #define DEFPACKSIZ    80    /* The default packet size */
  69. #define MAXFNAME 50 /* My maximum for filename length */
  70. #define SPOVER    14        /* The closest I may come to the end of the output
  71.                             buffer */
  72. #define MYTIME    10        /* Seconds after which I should be timed out */
  73. #define MYPAD    0        /* Number of padding characters I will need */
  74. #define MYPCHAR 0        /* Padding character I need (NULL) */
  75. #define MYEOL    '\r'    /* End-Of-Line character I need */
  76. #define MYQUOTE '#'        /* Quote character I will use */
  77. #define DEFQBIN 'Y'        /* I will do binary quoting */
  78. #define MYQBIN    '&'        /* Binary quoting character */
  79. #define DEFCHKT    '1'        /* Default Check sum type */
  80. #define MYCHKT    '1'        /* Check sum type */
  81. #define DEFREPT '~'        /* Repeat character I will use */
  82. #define MYREPT    '~'        /* Repeat character that I need */
  83. #define TRUE    -1        /* Boolean constants */
  84. #define FALSE    0
  85.  
  86.  
  87. /* Macro Definitions */
  88.  
  89. /*
  90.  * tochar: convert a control character to a printable one by adding a space.
  91.  *
  92.  * unchar: undoes tochar.
  93.  *
  94.  * ctl:        converts between control characters and printable characters by
  95.  *            toggling the control bit (ie. ^A becomes A and A becomes ^A).
  96.  */
  97.  
  98. #define tochar(ch)    ((ch) + ' ')
  99. #define unchar(ch)    ((ch) - ' ')
  100. #define ctl(ch)        ((ch) ^ 64)
  101.  
  102. /* Global Variables */
  103.  
  104. /* This is the format for the return packet from the other user */
  105. int
  106.     spsiz {MAXPACKSIZ},    /* Maximum send packet size */
  107.     timint {MYTIME},    /* Timeout for foreign host on sends */
  108.     pad {0};            /* How much padding to send */
  109. TEXT
  110.     padchar {0},        /* Padding character to send */
  111.     eol {MYEOL},        /* End-Of-Line character to send */
  112.     quote {MYQUOTE},    /* Quote character in incoming data */
  113.     qbin {0},            /* binary conversion character */
  114.     chkt {MYCHKT},        /* Checksum type '1','2', or '3' */
  115.     rept {0};            /* Repeat character if repeat supported */
  116.  
  117. int
  118.     size[2] {0},        /* Size of present data in packets */
  119.     empty[2] {0},        /* Packets ok to fill if zero */
  120.     pknum {0},            /* Current packet buffer index */
  121.     n {0},                /* Packet number */
  122.     nxo {0},            /* Output packet counter for display */
  123.     nxi {0},            /* Nak packet counter for display */
  124.     nxs {0},            /* Saved nak counter */
  125.     repeat_count {0},    /* Repeat counter for repeated characters */
  126.     numtry {0},            /* Times this packet retried */
  127.     oldtry {0},            /* Times previous packet retried */
  128.     iflg {0},            /* Indicates to turn on the image mode */
  129.     image {0},            /* -1 means 8-bit mode (driven by iflg) */
  130.     speed {0},            /* baud rate of the link */
  131.     fflg {0},            /* Indicates to send finish command */
  132.     rflg {0},            /* Indicates receive mode */
  133.     sflg {0},            /* Indicates send mode */
  134.     xflg {0},            /* Indicates server mode */
  135.     gflg {0},            /* Indicates get file mode */
  136.     vflg {0},            /* Verbose messages in server mode */
  137.     tflg {0},            /* Turn around flag */
  138.     pflg {0},            /* What kind of parity are we using? */
  139.     spflg {0},            /* This is our start-up parity flag */
  140.     debug {0},            /* indicates level of debugging output (0=none) */
  141.     filnamcnv {0},        /* -1 means do file name case conversions */
  142.     filecount {0};        /* Number of files left to send */
  143.  
  144. TEXT
  145.     state {0},            /* Present state of the automaton */
  146.     rqbin {0},            /* 8 bit quote character saved in rpar */
  147.     sqbin {0},            /* 8 bit quote character used in spar */
  148.     rrept {0},            /* Repeat character used in spar */
  149.     **filelist {0},        /* List of files to be sent */
  150.     *filnam {0},        /* Current file name */
  151.     *files[10] {0},        /* Pointers for the server file names */
  152.     filename_buffer[MAXPACKSIZ] {0}; /* Buffer for the server file name */
  153. TEXT
  154.     recpkt[MAXPACKSIZ] {0}, /* Receive packet buffer */
  155.     *packet[2] {0},        /* Packet pointers */
  156.     packet0[MAXPACKSIZ] {0}, /* Send packet zero buffer */
  157.     packet1[MAXPACKSIZ] {0}; /* Send packet one buffer */
  158.  
  159. FILE    ttyfd {0};        /* File descriptor of tty for I/O, 0 if remote */
  160.  
  161. FIO *fd {0};            /* pfio pointer */
  162. FIO    pfio {0};            /* Buffer structure for the files */
  163.  
  164. struct tty
  165.         ttymode {0},    /* tty raw mode */
  166.         savemode {0};    /* tty cooked mode */
  167.  
  168. struct {
  169.     int files;            /* Number of files */
  170.     int fc;                /* Number of characters in files */
  171.     int pli;            /* Number of packets received */
  172.     int plo;            /* Number of packets sent */
  173.     int cli;            /* Number of characters received */
  174.     int clo;            /* Number of characters sent */
  175.     ULONG time;            /* Total time for transaction */
  176.   } total {0}, file {0};
  177.  
  178. /*
  179.  *    m a i n
  180.  *
  181.  *    Main routine - parse command and options, set up the
  182.  *    tty lines, and dispatch to the appropriate routine.
  183.  *
  184.  */
  185.  
  186. main(argc,argv)
  187. int argc;                /* Character pointers to and count of */
  188. char **argv;            /* command line arguments */
  189.  
  190. {
  191.     TEXT *ttyname,        /* tty name for LINE argument */
  192.     *cp;                /* char pointer */
  193.  
  194.     printf("IDRIS Kermit - %s",KVERSION);
  195.     if (argc < 2)        /* Make sure there's a command line */
  196.         Usage("Invalid command line - Not enough arguments.");
  197.     packet[0] = &packet0;    /* Set up the packet pointers */
  198.     packet[1] = &packet1;
  199.  
  200.     /* Turn off the parse flags */
  201.     sflg = FALSE;
  202.     rflg = FALSE;
  203.     xflg = FALSE;
  204.     gflg = FALSE;
  205.     fflg = FALSE;
  206.     image = iflg = FALSE;
  207.     filnamcnv = TRUE;    /* conversion for UNIX systems */
  208.     vflg = FALSE;        /* Turn off verbose flags */
  209.     debug = FALSE;        /* Turn off the debug mode */
  210.     ttyname = 0;        /* We did not get a line assignment (pointer) */
  211.     speed = FALSE;        /* Speed not indicated */
  212.     spflg = pflg = FALSE;        /* Parity is not indicated */
  213.     tflg = FALSE;        /* No turn around character */
  214.  
  215.     sqbin = DEFQBIN;    /* Set up default qbin character */
  216.     rqbin = sqbin;    
  217.     qbin = FALSE;
  218.  
  219.     /* Reset the display counters */
  220.     nxo = 0;
  221.     nxi = 0;
  222.     nxs = -1;
  223.  
  224.     getflags(&argc,&argv,\
  225.         "s,r,x,g,f,i,u,v,d#,l*,b#,p?,t:F <file>",\
  226.         &sflg, &rflg, &xflg, &gflg, &fflg, &iflg, &filnamcnv, &vflg,\
  227.         &debug, &ttyname, &speed, &pflg, &tflg);
  228.  
  229.     if (!ttyname)            /* If LINE was not specified, use default */
  230.         ttyname = "/dev/lnk0";
  231.     ttyfd = open(ttyname, UPDATE, 0);/* Open the tty line */
  232.     if (ttyfd <= 0)
  233.         Usage("Cannot open %s.",ttyname);
  234.     
  235.     /* Put the proper tty into the correct mode */
  236.     egtty(ttyfd,&savemode); /* save for later use */
  237.     egtty(ttyfd,&ttymode);    /* set for changing the setup */
  238.  
  239.         printf("IDRIS Kermit - %s",KVERSION);
  240.     vflg = vflg ? vflg : fflg || gflg || rflg || sflg || debug ?
  241.          TRUE : FALSE;
  242.  
  243.     if ((gflg + xflg + rflg + sflg) != 1)    /* Only one command allowed */
  244.         if (!fflg)
  245.             Usage("Only one command allowed - g ! r ! s ! x.");
  246.  
  247.     if (fflg && (xflg || rflg))
  248.         Usage("Finish with server or receive?");
  249.  
  250.     if (!pflg)                /* Do we set up the parity? */
  251.     {
  252.         /* Check for raw mode and if true then force no parity */
  253.         if (ttymode.t_mode & M_RAW) pflg = FALSE;
  254.         else
  255.         {
  256.             /* What has the caller set into the hardware */
  257.             switch (ttymode.t_mode & (M_EVEN | M_ODD))
  258.             {
  259.             case M_ODD:
  260.                 pflg = 'o';
  261.                 break;
  262.             case M_EVEN:
  263.                 pflg = 'e';
  264.                 break;
  265.             case M_EVEN | M_ODD:
  266.                 pflg = 'm';
  267.                 break;
  268.             case 0:
  269.                 pflg = 's';
  270.             }
  271.         }
  272.     }
  273.     else
  274.     {
  275.         if (scnbuf("neoms",5,pflg) == 5)
  276.             Usage("Improper parity call out.");
  277.         if (pflg == 'n') pflg = FALSE;    /* If no parity then set it */
  278.     }
  279.     spflg = pflg;        /* Set up start-up parity */
  280.  
  281.     /* Put the hardware into raw mode */
  282.     ttymode.t_mode = (M_RAW | M_ALL | MR_XON);
  283.  
  284.     if (speed)            /* Do we set up the speed? */
  285.     {
  286.         switch (speed)
  287.         {
  288.             case 110:
  289.                 speed = B110;
  290.                 ttymode.t_mode |= M_2STOP;
  291.                 break;
  292.             case 150:
  293.                 speed = B150;
  294.                 break;
  295.             case 300:
  296.                 speed = B300;
  297.                 break;
  298.             case 1200:
  299.                 speed = B1200;
  300.                 break;
  301.             case 2400:
  302.                 speed = B2400;
  303.                 break;
  304.             case 4800:
  305.                 speed = B4800;
  306.                 break;
  307.             case 9600:
  308.                 speed = B9600;
  309.                 break;
  310.             default:
  311.                 Usage("Bad line speed.");
  312.         }
  313.         ttymode.t_ispeed = speed;
  314.         ttymode.t_ospeed = speed;
  315.     }
  316.     /* Set up the time-out and buffer size */
  317.     ttymode.t_min = 128;
  318.     ttymode.t_time = MYTIME * 10;
  319.     if (tflg)                /* Turn around flag on? */
  320.         ttymode.t_cgo = NULL;    /* Turn off XON in XON/XOFF */
  321.  
  322.     estty(ttyfd,&ttymode);    /* Put asg'd tty in requested mode */
  323.  
  324.     /* All set up, now execute the command that was given. */
  325.  
  326.     if (filnamcnv > 0)    /* Do we want to do file name conversions? */
  327.         filnamcnv = FALSE;
  328.  
  329.     if (iflg)            /* Turn on the image mode? */
  330.     {
  331.         image = TRUE;
  332.         /* Test the parity and make a determination of the qbin
  333.             mode info */
  334.         if (pflg)            /* Pflg contains the parity bit if set */
  335.             sqbin = MYQBIN;        /* Set 8-bit quoting */
  336.         else
  337.             sqbin = DEFQBIN;    /* We can do 8 bit transfers */
  338.     }
  339.  
  340.     if (debug)
  341.     {
  342.         printf("Main 1: S=%d, R=%d, X=%d, G=%d,", sflg, rflg, xflg, gflg);
  343.         printf(" F=%d, I=%d, U=%d, V=%d,", fflg, iflg, filnamcnv, vflg);
  344.         printf(" D=%d\n", debug);
  345.         printf("        L=%s, B=%d, P=%c,", ttyname, speed, pflg);
  346.         printf(" T=%d\n", tflg);
  347.         printf("Main 2: Bits for ttyfd %x\n",ttymode.t_mode);
  348.     }
  349.     if (gflg || sflg)
  350.     {
  351.         /* Anything to get or send? */
  352.         if (argc--)
  353.             filnam = *argv++;    /* Get file to send */
  354.         else
  355.         {
  356.             savemode.t_time = 0;
  357.             estty(ttyfd,&savemode); /* restore the old mode */
  358.             Usage("File name required.");
  359.                                 /* and give error */
  360.         }
  361.         fd = NULL;        /* Indicate no file open yet */
  362.         filelist = argv;    /* Set up the rest of the file list */
  363.         filecount = argc;    /* Number of files left to get or send */
  364.     }
  365.  
  366.     dostat(1);
  367.  
  368.     if (gflg)        /* Get command */
  369.     {
  370.         if (debug) printf("Main 3: Get command\n");
  371.         if (getsw() == FALSE)
  372.             Usage("Get failed.");
  373.         else
  374.             printmsg("Get done.");
  375.     }
  376.  
  377.     if (sflg)        /* Send command */ 
  378.     {
  379.         if (debug) printf("Main 4: Send command\n");
  380.         if (sendsw() == FALSE)    /* Send the file(s) */
  381.             Usage("Send failed.");    /* Report failure */
  382.         else            /*    or */
  383.             printmsg("Send done.");        /* success */
  384.     }
  385.     /* end of sflg */
  386.  
  387.     if (rflg)            /* Receive command */
  388.     {
  389.         if (debug) printf("Main 5: Receive command\n");
  390.         if (debug < 3)
  391.         {
  392.             if (recsw() == FALSE)    /* Receive the file(s) */
  393.                 Usage("Receive failed.");
  394.             else            /* Report failure */
  395.                 printmsg("Receive done.");    /* or success */
  396.         }
  397.         /* End of test for no receive of data (debug < 3) */
  398.     }
  399.     /* End of (rflg) test */
  400.  
  401.     if (xflg) 
  402.         while (server() == TRUE);
  403.  
  404.     if (fflg) 
  405.     {
  406.         if (debug) printf("Main 6: Finish command\n");
  407.             if (finishsw() == FALSE)
  408.                 Usage("Finish failed.");
  409.             else
  410.                 printmsg("Finish done.");
  411.     }
  412.  
  413.     if (vflg)
  414.         if(total.files > 1)
  415.         {
  416.             printf("%d Files\n", total.files);
  417.             printf("%d Bytes   %d Seconds   %d/%d Packets",
  418.                 total.fc, total.time, total.plo, total.pli);
  419.             printf("   %d/%d Characters\n", total.clo, total.cli);
  420.         }
  421.  
  422.     /* Restore the tty (reset the timeout to infinite) */
  423.     savemode.t_time = 0;
  424.     estty(ttyfd,&savemode);
  425.     exit(YES);
  426. }
  427.  
  428. /*
  429.  *    s e n d s w
  430.  *
  431.  *    Sendsw is the state table switcher for sending files.  It loops until
  432.  *    either it finishes, or an error is encountered.    The routines called
  433.  *    by sendsw are responsible for changing the state.
  434.  *
  435.  */
  436.  
  437. sendsw()
  438. {
  439.     TEXT sinit(), sfile(), sdata(), seof(), sbreak();
  440.  
  441.     n = 0;                    /* Initialize message number */
  442.     numtry = 0;                /* Say no tries yet */
  443.     state = 'S';            /* Send initiate is the start state */
  444.     while(TRUE)                /* Do this as long as necessary */
  445.     {
  446.         if (debug) printf("Sendsw 1: State: %c\n",state);
  447.         switch(state)
  448.         {
  449.         case 'S':    state = sinit();    break; /* Send-Init */
  450.         case 'T':    state = sfile();    break; /* Send-File */
  451.         case 'E':    state = sdata();    break; /* Send-Data */
  452.         case 'Z':    state = seof();    break; /* Send-End-of-File */
  453.         case 'B':    state = sbreak(); break; /* Send-Break */
  454.         case 'C':    return (TRUE);        /* Complete */
  455.         case 'A':                         /* "Abort" */
  456.         default:    return (FALSE);    /* Unknown, fail */
  457.         }
  458.     }
  459. }
  460.  
  461. /*
  462.  *    r e c s w
  463.  *
  464.  *    This is the state table switcher for receiving files.
  465.  *
  466.  */
  467.  
  468. recsw()
  469. {
  470.     TEXT rinit(), rfile(), rdata(); /* Use these procedures */
  471.  
  472.     n = 0;                    /* Initialize message number */
  473.     numtry = 0;                /* Say no tries yet */
  474.     state = 'R';            /* Receive-Init is the start state */
  475.     while(TRUE)
  476.     {
  477.         if (debug) printf("Recsw 1: state: %c\n",state);
  478.         switch(state)            /* Do until done */
  479.         {
  480.         case 'R':    state = rinit(); break; /* Receive-Init */
  481.         case 'F':    state = rfile(); break; /* Receive-File */
  482.         case 'D':    state = rdata(); break; /* Receive-Data */
  483.         case 'C':    return (TRUE);        /* Complete state */
  484.         case 'A':
  485.         default:    return (FALSE);        /* "Abort" state */
  486.         }
  487.     }
  488. }
  489.  
  490. /*
  491.  * g e t s w
  492.  *
  493.  * Get a file from the other end
  494.  *
  495.  */
  496.  
  497. getsw()
  498. {
  499.     TEXT ginit(), iinit(), rfile(), rdata(); /* Use these procedures */
  500.     TEXT filnam1[MAXFNAME],
  501.     *newfilnam,
  502.     *cp;
  503.     int num, len;
  504.  
  505.     cpystr(filnam1, filnam, NULL);    /* Copy file name */
  506.     newfilnam = cp = filnam1;
  507.     while (*cp != '\0')
  508.         if (*cp++ == '/')
  509.             newfilnam = cp;
  510.     if (filnamcnv)            /* Convert lower case to upper */
  511.         for (cp = newfilnam; *cp != '\0'; cp++)
  512.             *cp = toupper(*cp);
  513.     len = cp - newfilnam;
  514.     printmsg("Requesting %s as %s",filnam, newfilnam);
  515.     n = 0;                    /* Initialize message number */
  516.     numtry = 0;                /* Say no tries yet */
  517.     state = 'S';
  518.     while (TRUE)
  519.     {
  520.         if (debug) printf("Getsw 1: State: %c\n",state);
  521.         switch (state)
  522.         {
  523.         case 'S':    state = iinit(); break; /* Try this */
  524.         /* Then this */
  525.         case 'R':    state = ginit(len,newfilnam); break;
  526.         case 'F':    state = rfile(); break;    /* Fetch file name */
  527.         case 'D':    state = rdata(); break;    /* Fetch the data */
  528.         case 'C':    return (TRUE);    /* End it all goodly */
  529.         case 'A':
  530.         default:    return (FALSE);    /* End it all badly */
  531.         }
  532.     }
  533. }
  534.  
  535. /*
  536.  *    s e r v e r
  537.  *
  538.  *    This is the state table switcher for the server mode
  539.  *
  540.  */
  541.  
  542. server()
  543. {
  544.     TEXT xinit(), rfile(), rdata(); /* Use these procedures */
  545.     TEXT sinit(), xfile(), sdata(), seof(), sbreak(); /* and these */
  546.  
  547.     image=iflg;
  548.     pflg=spflg;
  549.     n = 0;                    /* Initialize message number */
  550.     numtry = 0;                /* Say no tries yet */
  551.     state = 'X';            /* Begin is the start state */
  552.     while(TRUE)
  553.     {
  554.         if (debug) printf("Server 1: state: %c\n",state);
  555.         switch(state)            /* Do until done */
  556.         {
  557.         case 'X':    state = xinit(); break;    /* Fetch what to do */
  558.         case 'S':    state = sinit(); break;    /* Send init packets */
  559.         case 'T':    state = xfile(); break;    /* maybe open file */
  560.         case 'E':    state = sdata(); break;    /* Send the data */
  561.         case 'Z':    state = seof(); break;
  562.         case 'B':    state = sbreak(); break;
  563.         case 'F':    state = rfile(); break; /* Receive-File */
  564.         case 'D':    state = rdata(); break; /* Receive-Data */
  565.         case 'C':    return (TRUE);            /* Complete state */
  566.         case 'G':    return (FALSE);            /* Finish command */
  567.         case 'A':
  568.         default:    return (debug ? FALSE : TRUE);
  569.         }
  570.     }
  571. }
  572.  
  573. /*
  574.  *    f i n i s h s w
  575.  *
  576.  *    finishsw is the state table switcher for sending general commands
  577.  * It loops until
  578.  *    either it finishes, or an error is encountered.    The routines called
  579.  *    by finishsw are responsible for changing the state.
  580.  *
  581.  */
  582.  
  583. finishsw()
  584. {
  585.     TEXT sfinish();
  586.     n = 0;                    /* Initialize message number */
  587.     numtry = 0;                /* Say no tries yet */
  588.     state = 'F';            /* Send finish is the start state */
  589.     while(TRUE)                /* Do this as long as necessary */
  590.     {
  591.         if (debug) printf("Finishsw 1: State: %c\n",state);
  592.         switch(state)
  593.         {
  594.         case 'F':    state = sfinish();    break; /* Send-Finish command */
  595.         case 'C':    return (TRUE);        /* Complete */
  596.         case 'A':                        /* "Abort" */
  597.         default:    return (FALSE);        /* Unknown, fail */
  598.         }
  599.     }
  600. }
  601.  
  602. /*
  603.  *    i i n i t
  604.  *
  605.  *    Initiate: send this host's parameters and get other side's back.
  606.  *
  607.  */
  608.  
  609. TEXT iinit()
  610. {
  611.     int num, len, slen;            /* Packet number, length */
  612.  
  613.     if (numtry++ > 2) return ('R'); /* If too many tries, give up */
  614.     slen = spar(packet0);        /* Fill up init info packet */
  615.  
  616.     flushinput();            /* Flush pending input */
  617.  
  618.     eol = MYEOL;            /* Preset to my eol character */
  619.     spack('I',n,slen,packet0); /* Send an I packet */
  620.     switch(rpack(&len,&num,recpkt)) /* What was the reply? */
  621.     {
  622.  
  623.     case 'Y':                /* ACK */
  624.         if (n != num)        /* If wrong ACK, stay in S state */
  625.         {                    /* Wrong packet number */
  626.     case 'N':                /* NAK, Try it again */
  627.     case FALSE:
  628.             nxi++;
  629.             return (state);
  630.         }
  631.         if (!rpar(recpkt,&len))    /* Get the other side's init data */
  632.             return ('A');        /* error with the packet parameters */
  633.  
  634.  
  635.         nxtpkt();
  636.         n = 0;                /* Reset packet number to zero */
  637.         return ('R');        /* OK, switch state to R */
  638.  
  639.     case 'E':                /* Error packet received */
  640.         prerrpkt(recpkt);    /* Print it out and */
  641.     default:
  642.          return ('A');        /* Anything else, just "abort" */
  643.     }
  644.  }
  645.  
  646. /*
  647.  *    s i n i t
  648.  *
  649.  *    Send Initiate: send this host's parameters and get other side's back.
  650.  */
  651.  
  652. TEXT sinit()
  653. {
  654.     int num, len, slen;            /* Packet number, length */
  655.  
  656.     if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
  657.     slen = spar(packet0);        /* Fill up init info packet */
  658.  
  659.     flushinput();            /* Flush pending input */
  660.  
  661.     eol = MYEOL;            /* Preset to my eol character */
  662.     spack('S',n,slen,packet0); /* Send an S packet */
  663.     switch(rpack(&len,&num,recpkt)) /* What was the reply? */
  664.     {
  665.  
  666.     case 'Y':                /* ACK */
  667.         if (n != num)        /* If wrong ACK, stay in S state */
  668.         {                    /* Wrong packet number */
  669.     case 'N':                /* NAK, Try it again */
  670.     case FALSE:
  671.             nxi++;
  672.             return (state);
  673.         }
  674.         if (!rpar(recpkt,&len))    /* Get the other side's init data */
  675.             return ('A');        /* error with the packet parameters */
  676.  
  677.  
  678.         nxtpkt();
  679.         return ('T');        /* OK, switch state to T */
  680.  
  681.     case 'E':                /* Error packet received */
  682.         prerrpkt(recpkt);    /* Print it out and */
  683.     default:
  684.          return ('A');        /* Anything else, just "abort" */
  685.     }
  686.  }
  687.  
  688. /*
  689.  *    r i n i t
  690.  *
  691.  *    Receive Initialization
  692.  */
  693.     
  694. TEXT rinit()
  695. {
  696.     int len, num, slen;            /* Packet length, number */
  697.  
  698.     if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */
  699.  
  700.     switch(rpack(&len,&num,recpkt)) /* Get a packet */
  701.     {
  702.     case 'S':            /* Send-Init packet */
  703.         if (!rpar(recpkt,&len))    /* Get the other side's init data */
  704.             return ('A');        /* error with the packet parameters */
  705.         slen = spar(packet0);    /* Fill up packet with my init info */
  706.         spack('Y',n,slen,packet0); /* ACK with my parameters */
  707.         oldtry = numtry;    /* Save old try count */
  708.         nxtpkt();
  709.         return ('F');        /* Enter File-Receive state */
  710.  
  711.     case FALSE:            /* Didn't get packet */
  712.         nxi++;
  713.         spack('N',n,0,0);    /* Return a NAK */
  714.         return (state);        /* Keep trying */
  715.  
  716.     case 'E':            /* Error packet received */
  717.         prerrpkt(recpkt);    /* Print it out and */
  718.     default:
  719.         return ('A');        /* Some other packet type, "abort" */
  720.     }
  721. }
  722. /* pe7mai.c End-of-file */
  723.