home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / cieregulus / cie680.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  47KB  |  1,285 lines

  1. /*
  2.  *  K e r m i t  File Transfer Utility   (in the C Programming Language)
  3.  *
  4.  *  UNIX Kermit, Columbia University, 1981, 1982, 1983
  5.  *      Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
  6.  *
  7.  *  Also:   Jim Guyton, Rand Corporation
  8.  *          Walter Underwood, Ford Aerospace
  9.  *            David Lawyer, UCI l986
  10.  *            Keith Justice, UCI l986
  11.  *
  12.  *  usage:  kermit c [lbe line baud escapechar]         to connect
  13.  *          kermit s [d..iflb line baud] file ...       to send files
  14.  *          kermit r [d..iflb line baud]                to receive files
  15.  *
  16.  *  where   c=connect, s=send, r=receive,
  17.  *          d=debug, i=image mode, f=no filename conversion, l=tty line,
  18.  *          b=baud rate, e=escape char.  dd=more verbose debugging.
  19.  *
  20.  *  For remote Kermit, format is either:
  21.  *          kermit r                                    to receive files
  22.  *  or      kermit s file ...                           to send files
  23.  *
  24.  *    A useful book: "Advanced Unix Programming" by Marc J. Rochkind, 1985.
  25.  *
  26.  *
  27.  *  History of Porting to the CIE:
  28.  *
  29.  *            Changes made are commented using only leading "//".
  30.  *    1986:    May 23:  Modified so as to be compatable with the CIE micro.
  31.  *            -Added #include <ucb/sys/ttydev.h> for speeds B1200 etc.
  32.  *            -Cast pointer subtraction results to integer (int) in:
  33.  *             1. sfile()  2. spack(...) in call of write(...)
  34.  *            -Changed name to CIE_Kermit: in printmsg(...)
  35.  *             June:  Modified Connect so that it works much faster.  Made
  36.  *            read non-blocking and read remote up to 80 ch. at a time.
  37.  *
  38.  *            Dec.: Changed Berkeley stty and gtty to Regulus (almost like
  39.  *            System III) ioctl calls via function setraw.  Changed many
  40.  *            0's to null pointers (long integers).  Did casting as indi-
  41.  *            cated by lint.  Deleted various options for non-CIE systems
  42.  *            except for UCB4X which  the CIE is assumed to be like, although
  43.  *            changes to the program have hopefully been made where there
  44.  *            is a difference between UCB4X and the CIE.
  45.  *
  46.  *            How to COMPILE:
  47.  *                                                          No flags are
  48.  *            needed for compiling, although one might use the flag for
  49.  *            system III: -ls3.  The command for compiling which I used:
  50.  *            cc -v -o kerm.c
  51.  */
  52.  
  53. #include <stdio.h>          /* Standard UNIX definitions */
  54.  
  55.  
  56. #define UCB4X       1       /* Berkeley 4.x UNIX */
  57.                                     //dsl added #includes
  58. #include <fcntl.h>                    //defines pars to open and fcntl
  59. #include <sys/ioctl.h>                //Regulus ioctl
  60. #include <termio.h>                    // Regulus termio structure see tty(dev)
  61. #include <signal.h>
  62. #include <setjmp.h>
  63.  
  64. /* Symbol Definitions */
  65.  
  66. #define MAXPACKSIZ  94      /* Maximum packet size */
  67. #define SOH         1       /* Start of header */
  68. #define CR          13      /* ASCII Carriage Return */
  69. #define SP          32      /* ASCII space */
  70. #define DEL         127     /* Delete (rubout) */
  71. #define ESCCHR      '^'     /* Default escape character for CONNECT */
  72.  
  73. #define MAXTRY      10      /* Times to retry a packet */
  74. #define MYQUOTE     '#'     /* Quote character I will use */
  75. #define MYPAD       0       /* Number of padding characters I will need */
  76. #define MYPCHAR     0       /* Padding character I need (NULL) */
  77.  
  78. #if IBM_UTS
  79. #define MYEOL       '\r'    /* End-Of-Line character for UTS systems */
  80. #else
  81. #define MYEOL       '\n'    /* End-Of-Line character I need */
  82. #endif
  83.  
  84. #define MYTIME      10      /* Seconds after which I should be timed out */
  85. #define MAXTIM      60      /* Maximum timeout interval */
  86. #define MINTIM      2       /* Minumum timeout interval */
  87.  
  88. #define TRUE        -1      /* Boolean constants */
  89. #define FALSE       0
  90.  
  91.  
  92. /* Macro Definitions */
  93.  
  94. /*
  95.  * tochar: converts a control character to a printable one by adding a space.
  96.  *
  97.  * unchar: undoes tochar.
  98.  *
  99.  * ctl:    converts between control characters and printable characters by
  100.  *         toggling the control bit (ie. ^A becomes A and A becomes ^A).
  101.  */
  102. #define tochar(ch)  ((ch) + ' ')
  103. #define unchar(ch)  ((ch) - ' ')
  104. #define ctl(ch)     ((ch) ^ 64 )
  105.  
  106.  
  107. /* Global Variables */
  108.  
  109. int     size,               /* Size of present data */
  110.         rpsiz,              /* Maximum receive packet size */
  111.         spsiz,              /* Maximum send packet size */
  112.         pad,                /* How much padding to send */
  113.         timint,             /* Timeout for foreign host on sends */
  114.         n,                  /* Packet number */
  115.         numtry,             /* Times this packet retried */
  116.         oldtry,             /* Times previous packet retried */
  117.         linefd,              /* File descriptor of tty for I/O, 0 if remote */
  118.         remote,             /* -1 means we're a remote kermit */
  119.         image,              /* -1 means 8-bit mode */
  120.         debug,              /* indicates level of debugging output (0=none) */
  121.         filnamcnv,          /* -1 means do file name case conversions */
  122.         filecount;          /* Number of files left to send */
  123.  
  124. char    state,              /* Present state of the automaton */
  125.         padchar,            /* Padding character to send */
  126.         eol,                /* End-Of-Line character to send */
  127.         escchr,             /* Connect command escape character */
  128.         quote,              /* Quote character in incoming data */
  129.         **filelist,         /* List of files to be sent */
  130.         *filnam,            /* Current file name */
  131.         recpkt[MAXPACKSIZ], /* Receive packet buffer */
  132.         packet[MAXPACKSIZ]; /* Packet buffer */
  133.  
  134. FILE    *fp,                /* File pointer for current disk file */
  135.         *log;               /* File pointer for Logfile */
  136.  
  137. jmp_buf env;                /* Environment ptr for timeout longjump */
  138.  
  139.  
  140. /*
  141.  *  m a i n
  142.  *
  143.  *  Main routine - parse command and options, set up the
  144.  *  tty lines, and dispatch to the appropriate routine.
  145.  */
  146.  
  147. main(argc,argv)
  148. int argc;                           /* Character pointers to and count of */
  149. char **argv;                            /* command line arguments */
  150. {
  151.     char *linename,                      /* tty name for LINE argument */
  152.         *cp;                            /* char pointer */
  153.     int speed,                          /* speed of assigned tty, */
  154.         cflg, rflg, sflg;               /* flags for CONNECT, RECEIVE, SEND */
  155.  
  156.     struct termio
  157.         ttyrawmode,                        /* Controlling tty raw mode */
  158.         ttycookmode,                     /* Controlling tty cooked mode */
  159.         linemode;                        /* mode of tty line in LINE option */
  160.  
  161.     if (argc < 2) usage();              /* Make sure there's a command line */
  162.  
  163.     cp = *++argv; argv++; argc -= 2;    /* Set up pointers to args */
  164.  
  165. /*  Initialize these values and hope the first packet will get across OK */
  166.  
  167.     eol = CR;                           /* EOL for outgoing packets */
  168.     quote = '#';                        /* Standard control-quote char "#" */
  169.     pad = 0;                            /* No padding */
  170.     padchar = '\0';                    // use null if any padding wanted
  171.  
  172.     speed = cflg = sflg = rflg = 0;     /* Turn off all parse flags */
  173.     linename = 0;                        /* Default is remote mode */
  174.  
  175. #if UCB4X                               /* Default to 7-bit masking, CRLF */
  176.     image = FALSE;                      /* translation and filename case */
  177.     filnamcnv = TRUE;                   /* conversion for UNIX systems */
  178. #else
  179.     image = TRUE;                       /* Default to no processing for */
  180.     filnamcnv = FALSE;                  /* non-UNIX systems */
  181. #endif
  182.  
  183.     escchr = ESCCHR;                    /* Default escape character */
  184.  
  185.     while ((*cp) != NULL)               /* Parse characters in first arg. */
  186.         switch (*cp++)
  187.         {
  188.             case 'c': cflg++; break;    /* C = Connect command */
  189.             case 's': sflg++; break;    /* S = Send command */
  190.             case 'r': rflg++; break;    /* R = Receive command */
  191.  
  192.             case 'd':                   /* D = Increment debug mode count */
  193.                 debug++; break;
  194.                 
  195.             case 'f':
  196.                 filnamcnv = FALSE;      /* F = don't do case conversion */
  197.                 break;                  /*     on filenames */
  198.  
  199.             case 'i':                   /* I = Image (8-bit) mode */
  200.                 image = TRUE; break;    /* (this is default for non-UNIX) */
  201.  
  202.             case 'l':                   /* L = specify tty line to use */
  203.                 if (argc--) linename = *argv++;
  204.                 else usage(); 
  205.                 if (debug) printf("Line to remote host is %s\n",linename); 
  206.                 break;
  207.                 
  208.             case 'e':                   /* E = specify escape char */
  209.                 if (argc--) escchr = **argv++;
  210.                 else usage();
  211.                 if (debug) printf("Escape char is \"%c\"\n",escchr);
  212.                 break;
  213.                 
  214.             case 'b':                   /* B = specify baud rate */
  215.                 if (argc--) speed = atoi(*argv++);
  216.                 else usage();
  217.                 if (debug) printf("Line speed to remote host is %d\n",speed);
  218.                 break;
  219.         }
  220.  
  221. /* Done parsing */
  222.  
  223.     if ((cflg+sflg+rflg) != 1)          /* Only one command allowed */
  224.         usage();
  225.  
  226.  
  227.     if (linename)                        /* If LINE was specified, we */
  228.     {                                   /* operate in local mode */
  229.         linefd = open( linename, O_RDWR|O_NDELAY ); //read/write & nonblock
  230.         if (linefd== -1) 
  231.         {
  232.             printmsg("Cannot open %s",linename);
  233.             exit(1);
  234.         }
  235.         remote = FALSE;                 /* Indicate we're in local mode */
  236.     }
  237.     else                                /* No LINE specified so we operate */
  238.     {                                   /* in remote mode (ie. controlling */
  239.         linefd = 0;                      /* tty is the communications line) */
  240.         remote = TRUE;
  241.     }
  242.  
  243.  
  244. /* Put the proper tty line into the correct mode */
  245.  
  246.     if (remote)                         /* If remote, use controlling tty */
  247.     {
  248.       ioctl(0,&ttycookmode);            /* Save current mode so we can */
  249.       ioctl(0,&ttyrawmode);               /* restore it later */
  250.  
  251.  
  252.         setraw(0,&linemode);        // Put remote tty into raw mode
  253.     }
  254.     else                                /* Local, use assigned line */
  255.     {
  256.  
  257.         ioctl(linefd,TCGETA,&linemode);    // Get line tty mode (attributes)
  258.         setraw(linefd, &linemode);        // Put line tty into raw mode
  259.  
  260.  
  261.  
  262.         if (speed)                      /* User specified a speed? */
  263.         {
  264.             switch(speed)               /* Get internal system code */
  265.             {
  266.                 case 300: speed = B300; break;
  267.                 case 1200: speed = B1200; break;
  268.                 case 2400: speed = B2400; break;
  269.                 case 4800: speed = B4800; break;
  270.                 case 9600: speed = B9600; break; 
  271.                 case 19200: speed = EXTA; break;
  272.  
  273.                 default:
  274.                     printmsg("Bad line speed.");
  275.                     exit(1);
  276.             }
  277.         linemode.c_cflag &= ~CBAUD;
  278.         linemode.c_cflag |= speed;
  279.         }
  280.         ioctl(linefd,TCSETA,&linemode);    // Put line tty in raw mode
  281.     }   
  282.  
  283.  
  284. /* All set up, now execute the command that was given. */
  285.  
  286.     if (debug)
  287.     {
  288.         printf("Debugging level = %d\n\n",debug);
  289.  
  290.         if (cflg) printf("Connect command\n\n");
  291.         if (sflg) printf("Send command\n\n");
  292.         if (rflg) printf("Receive command\n\n");
  293.     }
  294.   
  295.     if (cflg) connect();                /* Connect command */
  296.  
  297.     if (sflg)                           /* Send command */ 
  298.     {
  299.         if (argc--) filnam = *argv++;   /* Get file to send */
  300.         else
  301.         {   if (remote)
  302.                 ioctl(0,&ttycookmode);    /* Restore controlling tty's modes */
  303.             usage();                    /* and give error */
  304.         }
  305.         fp = NULL;                      /* Indicate no file open yet */
  306.         filelist = argv;                /* Set up the rest of the file list */
  307.         filecount = argc;               /* Number of files left to send */
  308.         if (sendsw() == FALSE)          /* Send the file(s) */
  309.             printmsg("Send failed.");   /* Report failure */
  310.         else                            /*  or */
  311.             printmsg("done.");          /* success */
  312.     }
  313.  
  314.     if (rflg)                           /* Receive command */
  315.     {
  316.         if (recsw() == FALSE)           /* Receive the file(s) */
  317.             printmsg("Receive failed.");
  318.         else                            /* Report failure */
  319.             printmsg("done.");          /* or success */
  320.     }
  321.  
  322.     if (remote) ioctl(0,TCSETA,&ttycookmode);//Restore controlling tty mode
  323. }
  324.  
  325.  
  326. /*
  327.  *  s e n d s w
  328.  *
  329.  *  Sendsw is the state table switcher for sending files.  It loops until
  330.  *  either it finishes, or an error is encountered.  The routines called
  331.  *  by sendsw are responsible for changing the state.
  332.  *
  333.  */
  334.  
  335. sendsw()
  336. {
  337.     char sinit(), sfile(), sdata(), seof(), sbreak();
  338.  
  339.     state = 'S';                        /* Send initiate is the start state */
  340.     n = 0;                              /* Initialize message number */
  341.     numtry = 0;                         /* Say no tries yet */
  342.     while(TRUE)                         /* Do this as long as necessary */
  343.     {
  344.         if (debug) printf("sendsw state: %c\n",state);
  345.         switch(state)
  346.         {
  347.             case 'S':   state = sinit();  break; /* Send-Init */
  348.             case 'F':   state = sfile();  break; /* Send-File */
  349.             case 'D':   state = sdata();  break; /* Send-Data */
  350.             case 'Z':   state = seof();   break; /* Send-End-of-File */
  351.             case 'B':   state = sbreak(); break; /* Send-Break */
  352.             case 'C':   return (TRUE);           /* Complete */
  353.             case 'A':   return (FALSE);          /* "Abort" */
  354.             default:    return (FALSE);          /* Unknown, fail */
  355.         }
  356.     }
  357. }
  358.  
  359.  
  360. /*
  361.  *  s i n i t
  362.  *
  363.  *  Send Initiate: send this host's parameters and get other side's back.
  364.  */
  365.  
  366. char sinit()
  367. {
  368.     int num, len;                       /* Packet number, length */
  369.  
  370.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  371.     spar(packet);                       /* Fill up init info packet */
  372.  
  373.     ioctl(linefd, TCFLSH, 0);              /* Flush pending input */
  374.  
  375.     spack('S',n,6,packet);              /* Send an S packet */
  376.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  377.     {
  378.         case 'N':  return(state);       /* NAK, try it again */
  379.  
  380.         case 'Y':                       /* ACK */
  381.             if (n != num)               /* If wrong ACK, stay in S state */
  382.                 return(state);          /* and try again */
  383.             rpar(recpkt);               /* Get other side's init info */
  384.  
  385.             if (eol == 0) eol = '\n';   /* Check and set defaults */
  386.             if (quote == 0) quote = '#';
  387.  
  388.             numtry = 0;                 /* Reset try counter */
  389.             n = (n+1)%64;               /* Bump packet count */
  390.             return('F');                /* OK, switch state to F */
  391.  
  392.         case 'E':                       /* Error packet received */
  393.             prerrpkt(recpkt);           /* Print it out and */
  394.             return('A');                /* abort */
  395.  
  396.         case FALSE: return(state);      /* Receive failure, try again */
  397.  
  398.         default: return('A');           /* Anything else, just "abort" */
  399.    }
  400.  }
  401.  
  402.  
  403. /*
  404.  *  s f i l e
  405.  *
  406.  *  Send File Header.
  407.  */
  408.  
  409. char sfile()
  410. {
  411.     int num, len;                       /* Packet number, length */
  412.     char filnam1[50],                   /* Converted file name */
  413.         *newfilnam,                     /* Pointer to file name to send */
  414.         *cp;                            /* char pointer */
  415.  
  416.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  417.     
  418.     if (fp == NULL)                     /* If not already open, */
  419.     {   if (debug) printf("   Opening %s for sending.\n",filnam);
  420.         fp = fopen(filnam,"r");         /* open the file to be sent */
  421.         if (fp == NULL)                 /* If bad file pointer, give up */
  422.         {
  423.             error("Cannot open file %s",filnam);
  424.             return('A');
  425.         }
  426.     }
  427.  
  428.     strcpy(filnam1, filnam);            /* Copy file name */
  429.     newfilnam = cp = filnam1;
  430.     while (*cp != '\0')                 /* Strip off all leading directory */
  431.         if (*cp++ == '/')               /* names (ie. up to the last /). */
  432.             newfilnam = cp;
  433.  
  434.     if (filnamcnv)                      /* Convert lower case to upper  */
  435.         for (cp = newfilnam; *cp != '\0'; cp++)
  436.             if (*cp >= 'a' && *cp <= 'z')
  437.                 *cp ^= 040;
  438.                                         //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  439.     len = (int) (cp - newfilnam);       // Compute length of new filename
  440.                                         // long pointer cast to int by dsl
  441.     printmsg("Sending %s as %s",filnam,newfilnam);
  442.  
  443.     spack('F',n,len,newfilnam);         /* Send an F packet */
  444.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  445.     {                   
  446.         case 'N':                       /* NAK, just stay in this state, */
  447.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  448.             if (n != num)               /* which is just like an ACK for */ 
  449.                 return(state);          /* this packet so fall thru to... */
  450.  
  451.         case 'Y':                       /* ACK */
  452.             if (n != num) return(state); /* If wrong ACK, stay in F state */
  453.             numtry = 0;                 /* Reset try counter */
  454.             n = (n+1)%64;               /* Bump packet count */
  455.             size = bufill(packet);      /* Get first data from file */
  456.             return('D');                /* Switch state to D */
  457.  
  458.         case 'E':                       /* Error packet received */
  459.             prerrpkt(recpkt);           /* Print it out and */
  460.             return('A');                /* abort */
  461.  
  462.         case FALSE: return(state);      /* Receive failure, stay in F state */
  463.  
  464.         default:    return('A');        /* Something else, just "abort" */
  465.     }
  466. }
  467.  
  468.  
  469. /*
  470.  *  s d a t a
  471.  *
  472.  *  Send File Data
  473.  */
  474.  
  475. char sdata()
  476. {
  477.     int num, len;                       /* Packet number, length */
  478.  
  479.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
  480.  
  481.     spack('D',n,size,packet);           /* Send a D packet */
  482.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  483.     {               
  484.         case 'N':                       /* NAK, just stay in this state, */
  485.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  486.             if (n != num)               /* which is just like an ACK for */
  487.                 return(state);          /* this packet so fall thru to... */
  488.                 
  489.         case 'Y':                       /* ACK */
  490.             if (n != num) return(state); /* If wrong ACK, fail */
  491.             numtry = 0;                 /* Reset try counter */
  492.             n = (n+1)%64;               /* Bump packet count */
  493.             if ((size = bufill(packet)) == EOF) /* Get data from file */
  494.                 return('Z');            /* If EOF set state to that */
  495.             return('D');                /* Got data, stay in state D */
  496.  
  497.         case 'E':                       /* Error packet received */
  498.             prerrpkt(recpkt);           /* Print it out and */
  499.             return('A');                /* abort */
  500.  
  501.         case FALSE: return(state);      /* Receive failure, stay in D */
  502.  
  503.         default:    return('A');        /* Anything else, "abort" */
  504.     }
  505. }
  506.  
  507.  
  508. /*
  509.  *  s e o f
  510.  *
  511.  *  Send End-Of-File.
  512.  */
  513.  
  514. char seof()
  515. {
  516.     int num, len;                       /* Packet number, length */
  517.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  518.  
  519.     spack('Z',n,0,packet);              /* Send a 'Z' packet */
  520.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  521.     {
  522.         case 'N':                       /* NAK, just stay in this state, */
  523.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
  524.             if (n != num)               /* which is just like an ACK for */
  525.                 return(state);          /* this packet so fall thru to... */
  526.  
  527.         case 'Y':                       /* ACK */
  528.             if (n != num) return(state); /* If wrong ACK, hold out */
  529.             numtry = 0;                 /* Reset try counter */
  530.             n = (n+1)%64;               /* and bump packet count */
  531.             if (debug) printf("   Closing input file %s, ",filnam);
  532.             fclose(fp);                 /* Close the input file */
  533.             fp = NULL;                  /* Set flag indicating no file open */ 
  534.  
  535.             if (debug) printf("looking for next file...\n");
  536.             if (gnxtfl() == FALSE)      /* No more files go? */
  537.                 return('B');            /* if not, break, EOT, all done */
  538.             if (debug) printf("   New file is %s\n",filnam);
  539.             return('F');                /* More files, switch state to F */
  540.  
  541.         case 'E':                       /* Error packet received */
  542.             prerrpkt(recpkt);           /* Print it out and */
  543.             return('A');                /* abort */
  544.  
  545.         case FALSE: return(state);      /* Receive failure, stay in Z */
  546.  
  547.         default:    return('A');        /* Something else, "abort" */
  548.     }
  549. }
  550.  
  551.  
  552. /*
  553.  *  s b r e a k
  554.  *
  555.  *  Send Break (EOT)
  556.  */
  557.  
  558. char sbreak()
  559. {
  560.     int num, len;                       /* Packet number, length */
  561.     if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  562.  
  563.     spack('B',n,0,packet);              /* Send a B packet */
  564.     switch (rpack(&len,&num,recpkt))    /* What was the reply? */
  565.     {
  566.         case 'N':                       /* NAK, just stay in this state, */
  567.             num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
  568.             if (n != num)               /* which is just like an ACK for */
  569.                 return(state);          /* this packet so fall thru to... */
  570.  
  571.         case 'Y':                       /* ACK */
  572.             if (n != num) return(state); /* If wrong ACK, fail */
  573.             numtry = 0;                 /* Reset try counter */
  574.             n = (n+1)%64;               /* and bump packet count */
  575.             return('C');                /* Switch state to Complete */
  576.  
  577.         case 'E':                       /* Error packet received */
  578.             prerrpkt(recpkt);           /* Print it out and */
  579.             return('A');                /* abort */
  580.  
  581.         case FALSE: return(state);      /* Receive failure, stay in B */
  582.  
  583.         default:    return ('A');       /* Other, "abort" */
  584.    }
  585. }
  586.  
  587.  
  588. /*
  589.  *  r e c s w
  590.  *
  591.  *  This is the state table switcher for receiving files.
  592.  */
  593.  
  594. recsw()
  595. {
  596.     char rinit(), rfile(), rdata();     /* Use these procedures */
  597.  
  598.     state = 'R';                        /* Receive-Init is the start state */
  599.     n = 0;                              /* Initialize message number */
  600.     numtry = 0;                         /* Say no tries yet */
  601.  
  602.     while(TRUE)
  603.     {
  604.         if (debug) printf(" recsw state: %c\n",state);
  605.         switch(state)                   /* Do until done */
  606.         {
  607.             case 'R':   state = rinit(); break; /* Receive-Init */
  608.             case 'F':   state = rfile(); break; /* Receive-File */
  609.             case 'D':   state = rdata(); break; /* Receive-Data */
  610.             case 'C':   return(TRUE);           /* Complete state */
  611.             case 'A':   return(FALSE);          /* "Abort" state */
  612.         }
  613.     }
  614. }
  615.  
  616.     
  617. /*
  618.  *  r i n i t
  619.  *
  620.  *  Receive Initialization
  621.  */
  622.   
  623. char rinit()
  624. {
  625.     int len, num;                       /* Packet length, number */
  626.  
  627.     if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
  628.  
  629.     switch(rpack(&len,&num,packet))     /* Get a packet */
  630.     {
  631.         case 'S':                       /* Send-Init */
  632.             rpar(packet);               /* Get the other side's init data */
  633.             spar(packet);               /* Fill up packet with my init info */
  634.             spack('Y',n,6,packet);      /* ACK with my parameters */
  635.             oldtry = numtry;            /* Save old try count */
  636.             numtry = 0;                 /* Start a new counter */
  637.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  638.             return('F');                /* Enter File-Receive state */
  639.  
  640.         case 'E':                       /* Error packet received */
  641.             prerrpkt(recpkt);           /* Print it out and */
  642.             return('A');                /* abort */
  643.  
  644.         case FALSE:                     /* Didn't get packet */
  645.             spack('N',n,0,NULL);           /* Return a NAK */
  646.             return(state);              /* Keep trying */
  647.  
  648.         default:     return('A');       /* Some other packet type, "abort" */
  649.     }
  650. }
  651.  
  652.  
  653. /*
  654.  *  r f i l e
  655.  *
  656.  *  Receive File Header
  657.  */
  658.  
  659. char rfile()
  660. {
  661.     int num, len;                       /* Packet number, length */
  662.     char filnam1[50];                   /* Holds the converted file name */
  663.  
  664.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  665.  
  666.     switch(rpack(&len,&num,packet))     /* Get a packet */
  667.     {
  668.         case 'S':                       /* Send-Init, maybe our ACK lost */
  669.             if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  670.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  671.             {                           /* Yes, ACK it again with  */
  672.                 spar(packet);           /* our Send-Init parameters */
  673.                 spack('Y',num,6,packet);
  674.                 numtry = 0;             /* Reset try counter */
  675.                 return(state);          /* Stay in this state */
  676.             }
  677.             else return('A');           /* Not previous packet, "abort" */
  678.  
  679.         case 'Z':                       /* End-Of-File */
  680.             if (oldtry++ > MAXTRY) return('A');
  681.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  682.             {                           /* Yes, ACK it again. */
  683.                 spack('Y',num,0,NULL);
  684.                 numtry = 0;
  685.                 return(state);          /* Stay in this state */
  686.             }
  687.             else return('A');           /* Not previous packet, "abort" */
  688.  
  689.         case 'F':                       /* File Header (just what we want) */
  690.             if (num != n) return('A');  /* The packet number must be right */
  691.             strcpy(filnam1, packet);    /* Copy the file name */
  692.  
  693.             if (filnamcnv)              /* Convert upper case to lower */
  694.                 for (filnam=filnam1; *filnam != '\0'; filnam++)
  695.                     if (*filnam >= 'A' && *filnam <= 'Z')
  696.                         *filnam |= 040;
  697.  
  698.             if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
  699.             {
  700.                 error("Cannot create %s",filnam1); /* Give up if can't */
  701.                 return('A');
  702.             }
  703.             else                        /* OK, give message */
  704.                 printmsg("Receiving %s as %s",packet,filnam1);
  705.  
  706.             spack('Y',n,0,NULL);           /* Acknowledge the file header */
  707.             oldtry = numtry;            /* Reset try counters */
  708.             numtry = 0;                 /* ... */
  709.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  710.             return('D');                /* Switch to Data state */
  711.  
  712.         case 'B':                       /* Break transmission (EOT) */
  713.             if (num != n) return ('A'); /* Need right packet number here */
  714.             spack('Y',n,0,NULL);           /* Say OK */
  715.             return('C');                /* Go to complete state */
  716.  
  717.         case 'E':                       /* Error packet received */
  718.             prerrpkt(recpkt);           /* Print it out and */
  719.             return('A');                /* abort */
  720.  
  721.         case FALSE:                     /* Didn't get packet */
  722.             spack('N',n,0,NULL);           /* Return a NAK */
  723.             return(state);              /* Keep trying */
  724.  
  725.         default:    return ('A');       /* Some other packet, "abort" */
  726.     }
  727. }
  728.  
  729.  
  730. /*
  731.  *  r d a t a
  732.  *
  733.  *  Receive Data
  734.  */
  735.  
  736. char rdata()
  737. {
  738.     int num, len;                       /* Packet number, length */
  739.     if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
  740.  
  741.     switch(rpack(&len,&num,packet))     /* Get packet */
  742.     {
  743.         case 'D':                       /* Got Data packet */
  744.             if (num != n)               /* Right packet? */
  745.             {                           /* No */
  746.                 if (oldtry++ > MAXTRY)
  747.                     return('A');        /* If too many tries, abort */
  748.                 if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  749.                 {                       /* Previous packet again? */
  750.                     spack('Y',num,6,packet); /* Yes, re-ACK it */
  751.                     numtry = 0;         /* Reset try counter */
  752.                     return(state);      /* Don't write out data! */
  753.                 }
  754.                 else return('A');       /* sorry, wrong number */
  755.             }
  756.           /* Got data with right packet number */
  757.             bufemp(packet,len);         /* Write the data to the file */
  758.             spack('Y',n,0,NULL);           /* Acknowledge the packet */
  759.             oldtry = numtry;            /* Reset the try counters */
  760.             numtry = 0;                 /* ... */
  761.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  762.             return('D');                /* Remain in data state */
  763.  
  764.         case 'F':                       /* Got a File Header */
  765.             if (oldtry++ > MAXTRY)
  766.                 return('A');            /* If too many tries, "abort" */
  767.             if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  768.             {                           /* It was the previous one */
  769.                 spack('Y',num,0,NULL);     /* ACK it again */
  770.                 numtry = 0;             /* Reset try counter */
  771.                 return(state);          /* Stay in Data state */
  772.             }
  773.             else return('A');           /* Not previous packet, "abort" */
  774.  
  775.         case 'Z':                       /* End-Of-File */
  776.             if (num != n) return('A');  /* Must have right packet number */
  777.             spack('Y',n,0,NULL);           /* OK, ACK it. */
  778.             fclose(fp);                 /* Close the file */
  779.             n = (n+1)%64;               /* Bump packet number */
  780.             return('F');                /* Go back to Receive File state */
  781.  
  782.         case 'E':                       /* Error packet received */
  783.             prerrpkt(recpkt);           /* Print it out and */
  784.             return('A');                /* abort */
  785.  
  786.         case FALSE:                     /* Didn't get packet */
  787.             spack('N',n,0,NULL);           /* Return a NAK */
  788.             return(state);              /* Keep trying */
  789.  
  790.         default:     return('A');       /* Some other packet, "abort" */
  791.     }
  792. }
  793.  
  794. /*
  795.  *  c o n n e c t
  796.  *
  797.  *  Establish a virtual terminal connection with the remote host, over an
  798.  *  assigned tty line.  The buffer (buf[..]) size affects the per-
  799.  *    formance and the optimal size has not been determined.  If too
  800.  *  large the scrolling is jerky at 9600 baud.  If too small it
  801.  *  is slow due to the overhad costs of too many calls to read or
  802.  *  write.  If its over 512 bytes (the approximate size of the kernal
  803.  *  read or write buffer size (2 buffers), then errors occur.
  804.  *
  805.  */
  806.  
  807. connect()
  808. {
  809.     int no_bytes,                        // No. of bytes in buffer to xfer
  810.         connected;                      /* Boolean connect flag */
  811.     char bel = '\07',  buf[80],            // Bell.  Buffer for reading remote.
  812.         c;
  813.  
  814.     struct termio
  815.         ttyrawmode,                        /* Controlling tty raw mode */
  816.         ttycookmode;                     /* Controlling tty cooked mode */
  817.  
  818.     if (remote)                         /* Nothing to connect to in remote */
  819.     {                                   /* mode, so just return */
  820.         printmsg("No line specified for connection.");
  821.         return;
  822.     }
  823.  
  824.     ioctl(0,TCGETA,&ttycookmode);        /* Save current mode so we can */
  825.     ioctl(0,TCGETA,&ttyrawmode);          // Get existing mode to modify
  826.  
  827.     setraw(0, &ttyrawmode);            // Put your tty in raw mode
  828.     fcntl(linefd, F_SETFL, O_NDELAY);    // Makes reads of line non-blocking
  829.     fcntl(0, F_SETFL, O_NDELAY);        // Makes reads of tty non-blocking
  830.                                         // See fcntl(sys)
  831.  
  832.     printmsg("Connected to UCI data switch.\r");
  833.     connected = TRUE;               /* Put us in "connect mode" */
  834.  
  835.     while (connected)
  836.     {
  837.         if(read(0,&c,1)==1)            // Try to get a char. (non-blocking)
  838.         {
  839.             if ((c&0177) == escchr)     /* Check for escape character */
  840.             {
  841.                 fcntl(0,F_SETFL,02);    // Turn off O_NDELAY: make blocking
  842.                 read(0,&c,1);
  843.                 fcntl(0,F_SETFL,O_NDELAY);    // Makes reads non-blocking
  844.                 if ((c&0177) == escchr)
  845.                     write(linefd,&c,1);
  846.                 else
  847.                 switch (c&0177)
  848.                 {
  849.                     case 'c':
  850.                     case 'C':
  851.                         connected = FALSE;
  852.                         write(0,"\r\n",2);
  853.                         break;
  854.  
  855.                     case 'h':
  856.                     case 'H':
  857.                         write(0,"\r\nYes, I'm still here...\r\n",26);
  858.                         break;
  859.  
  860.                     default:
  861.                         write(0,&bel,1);
  862.                         break;
  863.                 }
  864.             }
  865.             else
  866.             {                           /* If not escape charater, */
  867.                 write(linefd,&c,1);      // Write it to remote computer
  868.             }
  869.         }                                // end of outer if part
  870.         else if (no_bytes = read(linefd,&buf,80) )    //Try to read remote
  871.             write(1,&buf,no_bytes);                    //Write it to local tty
  872.                                     //Writes only if no_bytes != 0
  873.     }                                    //end of while loop
  874.  
  875.     fcntl(0,F_SETFL,02);                // Turn off O_NDELAY: make blocking
  876.     ioctl(0,TCSETAW,&ttycookmode);        // Restore tty mode
  877.     printmsg("Disconnected from UCI data switch.");
  878.     return;                         /* Done */
  879. }
  880.  
  881. /*
  882.  *      KERMIT utilities.
  883.  */
  884.  
  885. clkint()                                /* Timer interrupt handler */
  886. {
  887.     longjmp(env,TRUE);                  /* Tell rpack to give up */
  888. }
  889.  
  890.  
  891. /*
  892.  *  s p a c k
  893.  *
  894.  *  Send a Packet
  895.  */
  896.  
  897. spack(type,num,len,data)
  898. char type, *data;
  899. int num, len;
  900. {
  901.     int i;                              /* Character loop counter */
  902.     char chksum, buffer[100];           /* Checksum, packet buffer */
  903.     register char *bufp;                /* Buffer pointer */
  904.  
  905.     if (debug>1)                        /* Display outgoing packet */
  906.     {    printf("In spack");
  907.         if (data != NULL)
  908.             data[len] = '\0';           /* Null-terminate data to print it */
  909.         printf("  spack type: %c\n",type);
  910.         printf("         num:  %d\n",num);
  911.         printf("         len:  %d\n",len);
  912.         if (data != NULL)
  913.             printf("        data: \"%s\"\n",data);
  914.     }
  915.   
  916.     bufp = buffer;                      /* Set up buffer pointer */
  917.     for (i=1; i<=pad; i++) write(linefd,&padchar,1); /* Issue any padding */
  918.  
  919.     *bufp++ = SOH;                      /* Packet marker, ASCII 1 (SOH) */
  920.     *bufp++ = tochar(len+3);            /* Send the character count */
  921.     chksum  = tochar(len+3);            /* Initialize the checksum */
  922.     *bufp++ = tochar(num);              /* Packet number */
  923.     chksum += tochar(num);              /* Update checksum */
  924.     *bufp++ = type;                     /* Packet type */
  925.     chksum += type;                     /* Update checksum */
  926.  
  927.     for (i=0; i<len; i++)               /* Loop for all data characters */
  928.     {
  929.         *bufp++ = data[i];              /* Get a character */
  930.         chksum += data[i];              /* Update checksum */
  931.     }
  932.     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  933.     *bufp++ = tochar(chksum);           /* Put it in the packet */
  934.     *bufp = eol;                        /* Extra-packet line terminator */
  935.     write(linefd, buffer, (int)(bufp - buffer + 1) );  //Send the packet
  936. }                                        // 3rd arg cast to int by dsl
  937.                                         //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
  938. /*
  939.  *  r p a c k
  940.  *
  941.  *  Read a Packet
  942.  */
  943.  
  944. rpack(len,num,data)
  945. int *len, *num;                         /* Packet length, number */
  946. char *data;                             /* Packet data */
  947. {
  948.     int i, done;                        /* Data character number, loop exit */
  949.     char t,                             /* Current input character */
  950.         type,                           /* Packet type */
  951.         cchksum,                        /* Our (computed) checksum */
  952.         rchksum;                        /* Checksum received from other host */
  953.  
  954.     if (setjmp(env)) return FALSE;      /* Timed out, fail */
  955.     signal(SIGALRM,clkint);             /* Setup the timeout */
  956.     if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
  957.     alarm(timint);
  958.  
  959.     while (t != SOH)                    /* Wait for packet header */
  960.     {
  961.         read(linefd,&t,1);
  962.         t &= 0177;                      /* Handle parity */
  963.     }
  964.  
  965.     done = FALSE;                       /* Got SOH, init loop */
  966.     while (!done)                       /* Loop to get a packet */
  967.     {
  968.         read(linefd,&t,1);               /* Get character */
  969.         if (!image) t &= 0177;          /* Handle parity */
  970.         if (t == SOH) continue;         /* Resynchronize if SOH */
  971.         cchksum = t;                    /* Start the checksum */
  972.         *len = unchar(t)-3;             /* Character count */
  973.  
  974.         read(linefd,&t,1);               /* Get character */
  975.         if (!image) t &= 0177;          /* Handle parity */
  976.         if (t == SOH) continue;         /* Resynchronize if SOH */
  977.         cchksum = cchksum + t;          /* Update checksum */
  978.         *num = unchar(t);               /* Packet number */
  979.  
  980.         read(linefd,&t,1);               /* Get character */
  981.         if (!image) t &= 0177;          /* Handle parity */
  982.         if (t == SOH) continue;         /* Resynchronize if SOH */
  983.         cchksum = cchksum + t;          /* Update checksum */
  984.         type = t;                       /* Packet type */
  985.  
  986.         for (i=0; i<*len; i++)          /* The data itself, if any */
  987.         {                               /* Loop for character count */
  988.             read(linefd,&t,1);           /* Get character */
  989.             if (!image) t &= 0177;      /* Handle parity */
  990.             if (t == SOH) continue;     /* Resynch if SOH */
  991.             cchksum = cchksum + t;      /* Update checksum */
  992.             data[i] = t;                /* Put it in the data buffer */
  993.         }
  994.         data[*len] = 0;                 /* Mark the end of the data */
  995.  
  996.         read(linefd,&t,1);               /* Get last character (checksum) */
  997.         rchksum = unchar(t);            /* Convert to numeric */
  998.         read(linefd,&t,1);               /* get EOL character and toss it */
  999.         if (!image) t &= 0177;          /* Handle parity */
  1000.         if (t == SOH) continue;         /* Resynchronize if SOH */
  1001.         done = TRUE;                    /* Got checksum, done */
  1002.     }
  1003.  
  1004. #if UCB4X
  1005.     alarm(0);                           /* Disable the timer interrupt */
  1006. #endif
  1007.  
  1008.     if (debug>1)                        /* Display incoming packet */
  1009.     {
  1010.         if (data != NULL)
  1011.             data[*len] = '\0';          /* Null-terminate data to print it */
  1012.         printf("  rpack type: %c\n",type);
  1013.         printf("         num:  %d\n",*num);
  1014.         printf("         len:  %d\n",*len);
  1015.         if (data != NULL)
  1016.             printf("        data: \"%s\"\n",data);
  1017.     }
  1018.                                         /* Fold in bits 7,8 to compute */
  1019.     cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  1020.  
  1021.     if (cchksum != rchksum) return(FALSE);
  1022.  
  1023.     return(type);                       /* All OK, return packet type */
  1024. }
  1025.  
  1026.  
  1027. /*
  1028.  *  b u f i l l
  1029.  *
  1030.  *  Get a bufferful of data from the file that's being sent.
  1031.  *  Only control-quoting is done; 8-bit & repeat count prefixes are
  1032.  *  not handled.
  1033.  */
  1034.  
  1035. bufill(buffer)
  1036. char buffer[];                          /* Buffer */
  1037. {
  1038.     int i,                              /* Loop index */
  1039.         t;                              /* Char read from file */
  1040.     char t7;                            /* 7-bit version of above */
  1041.  
  1042.     i = 0;                              /* Init data buffer pointer */
  1043.     while((t = getc(fp)) != EOF)        /* Get the next character */
  1044.     {
  1045.         t7 = t & 0177;                  /* Get low order 7 bits */
  1046.  
  1047.         if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
  1048.         {                                   /* special handling? */
  1049.             if (t=='\n' && !image)
  1050.             {                           /* Do LF->CRLF mapping if !image */
  1051.                 buffer[i++] = quote;
  1052.                 buffer[i++] = ctl('\r');
  1053.             }
  1054.             buffer[i++] = quote;        /* Quote the character */
  1055.             if (t7 != quote)
  1056.             {
  1057.                 t = ctl(t);             /* and uncontrolify */
  1058.                 t7 = ctl(t7);
  1059.             }
  1060.         }
  1061.         if (image)
  1062.             buffer[i++] = t;            /* Deposit the character itself */
  1063.         else
  1064.             buffer[i++] = t7;
  1065.  
  1066.         if (i >= spsiz-8) return(i);    /* Check length */
  1067.     }
  1068.     if (i==0) return(EOF);              /* Wind up here only on EOF */
  1069.     return(i);                          /* Handle partial buffer */
  1070. }
  1071.  
  1072.  
  1073. /*
  1074.  *      b u f e m p
  1075.  *
  1076.  *  Put data from an incoming packet into a file.
  1077.  */
  1078.  
  1079. bufemp(buffer,len)
  1080. char  buffer[];                         /* Buffer */
  1081. int   len;                              /* Length */
  1082. {
  1083.     int i;                              /* Counter */
  1084.     char t;                             /* Character holder */
  1085.  
  1086.     for (i=0; i<len; i++)               /* Loop thru the data field */
  1087.     {
  1088.         t = buffer[i];                  /* Get character */
  1089.         if (t == MYQUOTE)               /* Control quote? */
  1090.         {                               /* Yes */
  1091.             t = buffer[++i];            /* Get the quoted character */
  1092.             if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
  1093.                 t = ctl(t);             /* No, uncontrollify it */
  1094.         }
  1095.         if (t==CR && !image)            /* Don't pass CR if in image mode */
  1096.             continue;
  1097.  
  1098.         putc(t,fp);
  1099.     }
  1100. }
  1101.  
  1102.  
  1103. /*
  1104.  *  g n x t f l
  1105.  *
  1106.  *  Get next file in a file group
  1107.  */
  1108.  
  1109. gnxtfl()
  1110. {
  1111.     if (debug) printf("   gnxtfl: filelist = \"%s\"\n",*filelist);
  1112.     filnam = *(filelist++);
  1113.     if (filecount-- == 0) return FALSE; /* If no more, fail */
  1114.     else return TRUE;                   /* else succeed */
  1115. }
  1116.  
  1117.  
  1118. /*
  1119.  *  s p a r
  1120.  *
  1121.  *  Fill the data array with my send-init parameters
  1122.  *
  1123.  */
  1124.  
  1125. spar(data)
  1126. char data[];
  1127. {
  1128.     data[0] = tochar(MAXPACKSIZ);          /* Biggest packet I can receive */
  1129.     data[1] = tochar(MYTIME);           /* When I want to be timed out */
  1130.     data[2] = tochar(MYPAD);            /* How much padding I need */
  1131.     data[3] = ctl(MYPCHAR);             /* Padding character I want */
  1132.     data[4] = tochar(MYEOL);            /* End-Of-Line character I want */
  1133.     data[5] = MYQUOTE;                  /* Control-Quote character I send */
  1134. }
  1135.  
  1136.  
  1137. /*  r p a r
  1138.  *
  1139.  *  Get the other host's send-init parameters
  1140.  *
  1141.  */
  1142.  
  1143. rpar(data)
  1144. char data[];
  1145. {
  1146.     spsiz = unchar(data[0]);            /* Maximum send packet size */
  1147.     timint = unchar(data[1]);           /* When I should time out */
  1148.     pad = unchar(data[2]);              /* Number of pads to send */
  1149.     padchar = ctl(data[3]);             /* Padding character to send */
  1150.     eol = unchar(data[4]);              /* EOL character I must send */
  1151.     quote = data[5];                    /* Incoming data quote character */
  1152. }
  1153.  
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166. /*
  1167.  *    s e t r a w
  1168.  *
  1169.  *  Puts a specified tty interface (or line interface via a tty port)
  1170.  *  into raw mode.  See the help file (manual) tty (dev) for an
  1171.  *  explanation of the ioctl system call and the termio structure.
  1172.  *  They are almost the same as for Unix System III.  Unsetting
  1173.  *  (disabling) the symbolic constant flags ISTRIP and OPOST
  1174.  *  resulted in ^Q from the keyboard not restarting stopped output.
  1175.  *  Although they should be disabled for raw mode per various
  1176.  *  sources, they were not due to this problem.  The line disipline
  1177.  *  LD_FILXFR would not work so it was not used.
  1178.  */
  1179.  
  1180. setraw(ttyfd, ttymode)
  1181.     struct termio *ttymode;
  1182.     int    ttyfd;
  1183. {
  1184.     if( ioctl( ttyfd , TCGETA, ttymode) )    // Get ttymode to modify
  1185.         printmsg("Error getting ttymode");
  1186.  
  1187.         ttymode->c_iflag &= ~(BRKINT | ICRNL );
  1188.         ttymode->c_oflag &= ~(TAB3 | ONLCR );
  1189.         ttymode->c_lflag &= ~(ISIG|ECHO|ICANON);
  1190.         ttymode->c_cc[4]  = 1;                    // min # of chars
  1191.         ttymode->c_cc[5]  = 0;                    // timeout of reads
  1192.     if( ioctl( ttyfd, TCSETAF, ttymode) )    // put ttyfd in raw mode
  1193.         printmsg("Error in setraw() ioctl.  Line/tty not put in raw mode.");
  1194. }
  1195. //--------------------------------------------------------------------------
  1196.  
  1197.  
  1198. /*
  1199.  *  Kermit printing routines:
  1200.  *
  1201.  *  usage - print command line options showing proper syntax
  1202.  *  printmsg -  like printf with "Kermit: " prepended
  1203.  *  error - like printmsg if local kermit; sends a error packet if remote
  1204.  *  prerrpkt - print contents of error packet received from remote host
  1205.  */
  1206.  
  1207. /*
  1208.  *  u s a g e 
  1209.  *
  1210.  *  Print summary of usage info and quit
  1211.  */
  1212.  
  1213. usage()
  1214. {
  1215. #if UCB4X
  1216.     printf("Usage: kermit c[lbe line baud esc.char]      (connect mode)\n");
  1217.     printf("or:    kermit s[diflb line baud] file ...    (send mode)\n");
  1218.     printf("or:    kermit r[diflb line baud]             (receive mode)\n");
  1219. #else
  1220.     printf("Usage: kermit c[le line esc.char]            (connect mode)\n");
  1221.     printf("or:    kermit s[difl line] file ...          (send mode)\n");
  1222.     printf("or:    kermit r[difl line]                   (receive mode)\n");
  1223. #endif
  1224.     exit(1);
  1225. }
  1226.  
  1227. /*
  1228.  *  p r i n t m s g
  1229.  *
  1230.  *  Print message on standard output if not remote.
  1231.  */
  1232.  
  1233. /*VARARGS1*/
  1234. printmsg(fmt, a1, a2, a3, a4, a5)
  1235. char *fmt;
  1236. {
  1237.     if (!remote)
  1238.     {
  1239.         printf("CIE_Kermit: ");
  1240.         printf(fmt,a1,a2,a3,a4,a5);
  1241.         printf("\n");
  1242.         fflush(stdout);                 /* force output (UTS needs it) */
  1243.     }
  1244. }
  1245.  
  1246. /*
  1247.  *  e r r o r
  1248.  *
  1249.  *  Print error message.
  1250.  *
  1251.  *  If local, print error message with printmsg.
  1252.  *  If remote, send an error packet with the message.
  1253.  */
  1254.  
  1255. /*VARARGS1*/
  1256. error(fmt, a1, a2, a3, a4, a5)
  1257. char *fmt;
  1258. {
  1259.     char msg[80];
  1260.     int len;
  1261.  
  1262.     if (remote)
  1263.     {
  1264.         sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
  1265.         len = strlen(msg);
  1266.         spack('E',n,len,msg);           /* Send the error packet */
  1267.     }
  1268.     else
  1269.         printmsg(fmt, a1, a2, a3, a4, a5);
  1270.  
  1271.     return;
  1272. }
  1273.  
  1274. /*
  1275.  *  p r e r r p k t
  1276.  *
  1277.  *  Print contents of error packet received from remote host.
  1278.  */
  1279. prerrpkt(msg)
  1280. char *msg;
  1281. {
  1282.     printf("Kermit aborting with following error from remote host:\n%s\n",msg);
  1283.     return;
  1284. }
  1285.