home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 110_01 / umodem27.c < prev    next >
Text File  |  1984-03-03  |  31KB  |  1,025 lines

  1. #
  2.  
  3. /*
  4.  *  UMODEM -- Implements the "CP/M User's Group XMODEM" protocol and 
  5.  *          the TERM II File Transfer Protocol (FTP) Number 1 for
  6.  *            packetized file up/downloading.    
  7.  *
  8.  *    Note: UNIX System-Dependent values are indicated by the string [SD]
  9.  *          in a comment field one the same line as the values.
  10.  *
  11.  *         -- Lauren Weinstein, 6/81
  12.  *       -- (Version 2.0) Modified for JHU/UNIX by Richard Conn, 8/1/81
  13.  *       -- Version 2.1 Mods by Richard Conn, 8/2/81
  14.  *        . File Size Included on Send Option
  15.  *       -- Version 2.2 Mods by Richard Conn, 8/2/81
  16.  *        . Log File Generation and Option Incorporated
  17.  *       -- Version 2.3 Mods by Richard Conn, 8/3/81
  18.  *        . TERM II FTP 1 Supported
  19.  *        . Error Log Reports Enhanced
  20.  *        . CAN Function Added to FTP 3
  21.  *        . 'd' Option Added to Delete umodem.log File before starting
  22.  *       -- Version 2.4 Mods by Richard Conn, 8/4/81
  23.  *        . 16K-extent sector number check error corrected
  24.  *        . Count of number of received sectors added
  25.  *       -- Version 2.5 Mods by Richard Conn, 8/5/81
  26.  *        . ARPA Net Flag added
  27.  *        . ARPA Net parameter ('a') added to command line
  28.  *        . ARPA Net BIS, BIE, BOS, BOE added
  29.  *        . ARPA Net FFH escape added
  30.  *       -- Version 2.6 Mods by Bennett Marks, 8/21/81 (Bucky @ CCA-UNIX)
  31.  *        . mods for UNIX V7 (Note: for JHU compilation define
  32.  *          the variable JHU  during 'cc'
  33.  *        . added 'mungmode' flag to protect from inadvertant
  34.  *          overwrite on file receive
  35.  *        . changed timeout handling prior to issuing checksum
  36.  *       -- Version 2.7 Mods by Richard Conn, 8/25/81 (rconn @ BRL)
  37.  *        . correct minor "ifndef" error in which ifndef had no arg
  38.  *        . restructured "ifdef" references so that other versions
  39.  *          of UNIX than Version 7 and JHU can be easily incorporated;
  40.  *          previous ifdef references were for JHU/not JHU;
  41.  *          to compile under Version 7 or JHU UNIX, the following
  42.  *          command lines are recommended:
  43.  *            "cc -7 umodem.c -o umodem -DVER7" for Version 7
  44.  *            "cc -7 umodem.c -o umodem -DJHU" for JHU
  45.  *        . added 'y' file status display option; this option gives
  46.  *          the user an estimate of the size of the target file to
  47.  *          send from the UNIX system in terms of CP/M records (128
  48.  *          bytes) and Kbytes (1024 byte units)
  49.  *        . added '7' option which modifies the transmission protocols
  50.  *          for 7 significant bits rather than 8; modifies both FTP 1
  51.  *          and FTP 3
  52.  *
  53.  */
  54.  
  55. #include <stdio.h>
  56. #include <sys/types.h>
  57. #include <sys/stat.h>
  58.  
  59. /*  JHU UNIX tty parameter file  */
  60. #ifdef JHU
  61. #include <stty.h>
  62. #endif
  63.  
  64. /*  Version 7 UNIX tty parameter file  */
  65. #ifdef VER7
  66. #include <sgtty.h>
  67. #endif
  68.  
  69. #include <signal.h>
  70.  
  71. #define         VERSION    27    /* Version Number */
  72. #define         TRUE    1        
  73. #define      FALSE      0
  74. #define      SOH      001 
  75. #define         STX    002
  76. #define         ETX    003
  77. #define      EOT    004
  78. #define         ENQ    005
  79. #define      ACK      006
  80. #define         LF        012   /* Unix LF/NL */
  81. #define         CR        015  
  82. #define      NAK      025
  83. #define         SYN    026
  84. #define         CAN    030
  85. #define         ESC    033
  86. #define         CTRLZ    032   /* CP/M EOF for text (usually!) */
  87. #define      TIMEOUT      -1
  88. #define      ERRORMAX      10    /* maximum errors tolerated */
  89. #define      RETRYMAX      10    /* maximum retries to be made */
  90. #define         BBUFSIZ    128   /* buffer size -- do not change! */
  91. #define      CREATMODE    0644  /* mode for created files */
  92.  
  93. /*  ARPA Net Constants  */
  94. #define         IAC    0377
  95. #define         DO        0375
  96. #define         DONT    0376
  97. #define         WILL    0373
  98. #define         WONT    0374
  99. #define         TRBIN    0
  100.  
  101. /*  JHU UNIX structures  */
  102. #ifdef JHU
  103. struct sttybuf ttys, ttysnew, ttystemp;    /* for stty terminal mode calls */
  104. #endif
  105.  
  106. /*  Version 7 UNIX structures  */
  107. #ifdef VER7
  108. struct sgttyb  ttys, ttysnew, ttystemp;    /* for stty terminal mode calls */
  109. #endif
  110.  
  111. struct stat statbuf;      /* for terminal message on/off control */
  112. FILE *LOGFP, *fopen();
  113. char buff[BBUFSIZ];
  114.  
  115. #ifdef JHU
  116. int wason;
  117. #endif
  118.  
  119. #ifdef VER7
  120. int pagelen;
  121. #endif
  122.  
  123. char *tty;
  124. char XMITTYPE;
  125. int ARPA, RECVFLAG, SENDFLAG, FTP1, PMSG, DELFLAG, LOGFLAG, MUNGMODE;
  126. int STATDISP, BIT7, BITMASK;
  127. int delay;
  128.  
  129. alarmfunc();
  130.  
  131. main(argc, argv)
  132. int argc;
  133. char **argv;
  134. {
  135.     char *logfile;
  136.     int index;
  137.     char flag;
  138.  
  139.     logfile = "umodem.log";  /* Name of LOG File */
  140.  
  141.     printf("\nUMODEM Version %d.%d", VERSION/10, VERSION%10);
  142.     printf(" -- UNIX-Based Remote File Transfer Facility\n");
  143.  
  144.     if (argc < 3 || *argv[1] != '-')
  145.     {  printf("\nUsage:  \n\tumodem ");
  146.         printf("-[rb!rt!sb!st][p][l][1][a][m][d][y][7]");
  147.         printf(" filename\n");
  148.        printf("\n");
  149.        printf("\n\trb <-- Receive Binary");
  150.        printf("\n\trt <-- Receive Text");
  151.        printf("\n\tsb <-- Send Binary");
  152.        printf("\n\tst <-- Send Text");
  153.        printf("\n\tp  <-- Turn ON Parameter Display");
  154.        printf("\n\tl  <-- (ell) Turn OFF LOG File Entries");
  155.        printf("\n\t1  <-- (one) Employ TERM II FTP 1");
  156.        printf("\n\ta  <-- Turn ON ARPA Net Flag");
  157.        printf("\n\tm  <-- Allow file overwiting on receive");
  158.        printf("\n\td  <-- Delete umodem.log File before starting");
  159.        printf("\n\ty  <-- Display file status (size) information only");
  160.        printf("\n\t7  <-- Enable 7-bit transfer mask");
  161.        printf("\n");
  162.         exit(-1);
  163.     }
  164.  
  165.     index = 1;  /* set index for loop */
  166.     delay = 3;  /* assume FTP 3 delay */
  167.     PMSG = FALSE;  /* turn off flags */
  168.     FTP1 = FALSE;  /* assume FTP 3 (CP/M UG XMODEM2) */
  169.     RECVFLAG = FALSE;  /* not receive */
  170.     SENDFLAG = FALSE;  /* not send either */
  171.     XMITTYPE = 't';  /* assume text */
  172.     DELFLAG = FALSE;  /* do NOT delete log file before starting */
  173.     LOGFLAG = TRUE;  /* assume log messages */
  174.     ARPA = FALSE;  /* assume not on ARPA Net */
  175.     MUNGMODE = FALSE; /* protect files from overwriting */
  176.     STATDISP = FALSE;  /* assume not a status display */
  177.     BIT7 = FALSE;  /* assume 8-bit communication */
  178.     while ((flag = argv[1][index++]) != '\0')
  179.         switch (flag) {
  180.         case 'a' : ARPA = TRUE;  /* set ARPA Net */
  181.                break;
  182.         case 'p' : PMSG = TRUE;  /* print all messages */
  183.                break;
  184.         case '1' : FTP1 = TRUE;  /* select FTP 1 */
  185.                delay = 5;  /* FTP 1 delay constant */
  186.                printf("\nUMODEM:  TERM II FTP 1 Selected\n");
  187.                break;
  188.         case 'd' : DELFLAG = TRUE;  /* delete log file first */
  189.                break;
  190.         case 'l' : LOGFLAG = FALSE;  /* turn off log report */
  191.                break;
  192.         case 'r' : RECVFLAG = TRUE;  /* receive file */
  193.                XMITTYPE = gettype(argv[1][index++]);  /* get t/b */
  194.                break;
  195.         case 's' : SENDFLAG = TRUE;  /* send file */
  196.                XMITTYPE = gettype(argv[1][index++]);
  197.                break;
  198.         case 'm' : MUNGMODE = TRUE; /* allow overwriting of files */
  199.                break;
  200.         case 'y' : STATDISP = TRUE;  /* display file status */
  201.                break;
  202.         case '7' : BIT7 = TRUE;  /* transfer only 7 bits */
  203.                break;
  204.         default  : error("Invalid Flag", FALSE);
  205.         }
  206.  
  207.     if (BIT7 && (XMITTYPE == 'b'))
  208.     {  printf("\nUMODEM:  Fatal Error -- Both 7-Bit Transfer and ");
  209.        printf("Binary Transfer Selected");
  210.        exit(-1);  /* error exit to UNIX */
  211.     }
  212.  
  213.     if (BIT7)  /* set MASK value */
  214.        BITMASK = 0177;  /* 7 significant bits */
  215.     else
  216.        BITMASK = 0377;  /* 8 significant bits */
  217.  
  218.     if (PMSG)
  219.        { printf("\nSupported File Transfer Protocols:");
  220.          printf("\n\tTERM II FTP 1");
  221.          printf("\n\tCP/M UG XMODEM2 (TERM II FTP 3)");
  222.          printf("\n\n");
  223.        }
  224.  
  225.     if (LOGFLAG)
  226.        { if (!DELFLAG)
  227.         LOGFP = fopen(logfile, "a");  /* append to LOG file */
  228.          else
  229.         LOGFP = fopen(logfile, "w");  /* new LOG file */
  230.          fprintf(LOGFP,"\n\n++++++++\n");
  231.          fprintf(LOGFP,"\nUMODEM Version %d.%d\n", VERSION/10, VERSION%10);
  232.          printf("\nUMODEM:  LOG File '%s' is Open\n", logfile);
  233.        }
  234.  
  235.     if (STATDISP) yfile(argv[2]);  /* status of a file */
  236.  
  237.     if (RECVFLAG && SENDFLAG)
  238.         error("Both Send and Receive Functions Specified", FALSE);
  239.     if (!RECVFLAG && !SENDFLAG)
  240.         error("Neither Send nor Receive Functions Specified", FALSE);
  241.  
  242.     if (RECVFLAG)
  243.     {  if(open(argv[2], 0) != -1)  /* possible abort if file exists */
  244.        {    printf("\nUMODEM:  Warning -- Target File Exists\n");
  245.         if( MUNGMODE == FALSE )
  246.             error("Fatal - Can't overwrite file\n",FALSE);
  247.         printf("UMODEM:  Overwriting Target File\n");
  248.        }
  249.        rfile(argv[2]);  /* receive file */
  250.     }
  251.     else
  252.         sfile(argv[2]);  /* send file */
  253.  
  254. }
  255.  
  256. gettype(ichar)
  257. char ichar;
  258. {
  259.     if (ichar == 't') return(ichar);
  260.     if (ichar == 'b') return(ichar);
  261.     error("Invalid Send/Receive Parameter - not t or b", FALSE);
  262.     return;
  263. }
  264.  
  265. /* set tty modes for UMODEM transfers */
  266. setmodes()
  267. {
  268.  
  269. /*  Device characteristics for JHU UNIX  */
  270. #ifdef JHU    
  271.     if (gtty(0, &ttys) < 0)  /* get current tty params */
  272.         error("Can't get TTY Parameters", TRUE);
  273.  
  274.     tty = ttyname(0);  /* identify current tty */
  275.  
  276.     /* duplicate current modes in ttysnew structure */
  277.     ttysnew.ispeed = ttys.ispeed;    /* copy input speed */
  278.     ttysnew.ospeed = ttys.ospeed;    /* copy output speed */
  279.     ttysnew.xflags = ttys.xflags;    /* copy JHU/UNIX extended flags */
  280.     ttysnew.mode   = ttys.mode;    /* copy standard terminal flags */
  281.  
  282.     ttysnew.mode |= RAW;    /* set for RAW Mode */
  283.             /* This ORs in the RAW mode value, thereby
  284.                setting RAW mode and leaving the other
  285.                mode settings unchanged */
  286.     ttysnew.mode &= ~ECHO;  /* set for no echoing */
  287.             /* This ANDs in the complement of the ECHO
  288.                setting (for NO echo), thereby leaving all
  289.                current parameters unchanged and turning
  290.                OFF ECHO only */
  291.     ttysnew.mode &= ~XTABS;  /* set for no tab expansion */
  292.     ttysnew.mode &= ~LCASE;  /* set for no upper-to-lower case xlate */
  293.     ttysnew.mode |= ANYP;  /* set for ANY Parity */
  294.     ttysnew.mode &= ~NL3;  /* turn off ALL delays - new line */
  295.     ttysnew.mode &= ~TAB3; /* turn off tab delays */
  296.     ttysnew.mode &= ~CR3;  /* turn off CR delays */
  297.     ttysnew.mode &= ~FF1;  /* turn off FF delays */
  298.     ttysnew.mode &= ~BS1;  /* turn off BS delays */
  299.     /* the following are JHU/UNIX xflags settings; they are [SD] */
  300.     ttysnew.xflags &= ~PAGE;  /* turn off paging */
  301.     ttysnew.xflags &= ~STALL;  /* turn off ^S/^Q recognition */
  302.     ttysnew.xflags &= ~TAPE;  /* turn off ^S/^Q input control */
  303.     ttysnew.xflags &= ~FOLD;  /* turn off CR/LF folding at col 72 */
  304.     ttysnew.xflags |= NB8;  /* turn on 8-bit input/output */
  305.  
  306.     if (stty(0, &ttysnew) < 0)  /* set new params */
  307.         error("Can't set new TTY Parameters", TRUE);
  308.  
  309.     if (stat(tty, &statbuf) < 0)  /* get tty status */ 
  310.         error("Can't get your TTY Status", TRUE);
  311.  
  312.     if (statbuf.st_mode&011)  /* messages are on [SD] */
  313.     {    wason = TRUE;
  314.         if (chmod(tty, 020600) < 0)  /* turn off tty messages [SD] */
  315.             error("Can't change TTY Mode", TRUE);
  316.     }    
  317.     else
  318.         wason = FALSE;  /* messages are already off */
  319. #endif        
  320.  
  321. /*  Device characteristics for Version 7 UNIX  */
  322. #ifdef VER7
  323.     if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
  324.         error("Can't get TTY Parameters", TRUE);
  325.     tty = ttyname(0);  /* identify current tty */
  326.     
  327.     /* transfer current modes to new structure */
  328.     ttysnew.sg_ispeed = ttys.sg_ispeed;    /* copy input speed */
  329.     ttysnew.sg_ospeed = ttys.sg_ospeed;    /* copy output speed */
  330.     ttysnew.sg_erase  = ttys.sg_erase;    /* copy erase flags */
  331.     ttysnew.sg_flags  = ttys.sg_flags;    /* copy flags */
  332.      ttysnew.sg_kill   = ttys.sg_kill;    /* copy std terminal flags */
  333.     
  334.  
  335.     ttysnew.sg_flags |= RAW;    /* set for RAW Mode */
  336.             /* This ORs in the RAW mode value, thereby
  337.                setting RAW mode and leaving the other
  338.                mode settings unchanged */
  339.     ttysnew.sg_flags &= ~ECHO;  /* set for no echoing */
  340.             /* This ANDs in the complement of the ECHO
  341.                setting (for NO echo), thereby leaving all
  342.                current parameters unchanged and turning
  343.                OFF ECHO only */
  344.     ttysnew.sg_flags &= ~XTABS;  /* set for no tab expansion */
  345.     ttysnew.sg_flags &= ~LCASE;  /* set for no upper-to-lower case xlate */
  346.     ttysnew.sg_flags |= ANYP;  /* set for ANY Parity */
  347.     ttysnew.sg_flags &= ~NL3;  /* turn off ALL delays - new line */
  348.     ttysnew.sg_flags &= ~TAB2; /* turn off tab delays */
  349.     ttysnew.sg_flags &= ~CR3;  /* turn off CR delays */
  350.     ttysnew.sg_flags &= ~FF1;  /* turn off FF delays */
  351.     ttysnew.sg_flags &= ~BS1;  /* turn off BS delays */
  352.     ttysnew.sg_flags &= ~TANDEM;  /* turn off flow control */
  353.  
  354.     /* make sure page mode is off */
  355.     ioctl(0,TIOCSSCR,&pagelen);
  356.     
  357.     /* set new paramters */
  358.     if (ioctl(0,TIOCSETP,&ttysnew) < 0)
  359.         error("Can't set new TTY Parameters", TRUE);
  360.  
  361.     if (stat(tty, &statbuf) < 0)  /* get tty status */ 
  362.         error("Can't get your TTY Status", TRUE);
  363. #endif    
  364.  
  365.     if (PMSG)
  366.         { printf("\nUMODEM:  TTY Device Parameters Altered");
  367.           ttyparams();  /* print tty params */
  368.         }
  369.  
  370.     if (ARPA)  /* set 8-bit on ARPA Net */
  371.         setarpa();
  372.  
  373.     return;
  374. }
  375.  
  376. /*  set ARPA Net for 8-bit transfers  */
  377. setarpa()
  378. {
  379.     sendbyte(IAC);  /* set B O S (Binary Output Start) */
  380.     sendbyte(WILL);
  381.     sendbyte(TRBIN);
  382.  
  383.     sendbyte(IAC);  /* set B I S (Binary Input Start) */
  384.     sendbyte(DO);
  385.     sendbyte(TRBIN);
  386.  
  387.     sleep(3);  /* wait for TIP to configure */
  388.  
  389.     return;
  390. }
  391.  
  392. /* restore normal tty modes */
  393. restoremodes(errcall)
  394. int errcall;
  395. {
  396.     if (ARPA)  /* if ARPA Net, reconfigure */
  397.         resetarpa();
  398.  
  399. /*  Device characteristic restoration for JHU UNIX  */
  400. #ifdef JHU
  401.     if (wason)  /* if messages were on originally */
  402.         if (chmod(tty, 020611) < 0)  /*  [SD]  */
  403.             error("Can't change TTY Mode", FALSE);
  404.  
  405.     if (stty(0, &ttys) < 0)  /* restore original tty modes */
  406.         { if (!errcall)
  407.            error("RESET - Can't restore normal TTY Params", FALSE);
  408.         else
  409.            { printf("UMODEM:  ");
  410.              printf("RESET - Can't restore normal TTY Params\n");
  411.            }
  412.         }
  413. #endif
  414.  
  415. /*  Device characteristic restoration for Version 7 UNIX  */
  416. #ifdef VER7
  417.     if (ioctl(0,TIOCSETP,&ttys) < 0)
  418.         { if (!errcall)
  419.            error("RESET - Can't restore normal TTY Params", FALSE);
  420.         else
  421.            { printf("UMODEM:  ");
  422.              printf("RESET - Can't restore normal TTY Params\n");
  423.            }
  424.         }
  425. #endif
  426.  
  427.     if (PMSG)
  428.         { printf("\nUMODEM:  TTY Device Parameters Restored");
  429.           ttyparams();  /* print tty params */
  430.         }
  431.  
  432.     return;
  433. }
  434.  
  435. /* reset the ARPA Net */
  436. resetarpa()
  437. {
  438.     sendbyte(IAC);  /* send B O E (Binary Output End) */
  439.     sendbyte(WONT);
  440.     sendbyte(TRBIN);
  441.  
  442.     sendbyte(IAC);  /* send B I E (Binary Input End) */
  443.     sendbyte(DONT);
  444.     sendbyte(TRBIN);
  445.  
  446.     return;
  447. }
  448.  
  449. /* print error message and exit; if mode == TRUE, restore normal tty modes */
  450. error(msg, mode)
  451. char *msg;
  452. int mode;
  453. {
  454.     if (mode)
  455.         restoremodes(TRUE);  /* put back normal tty modes */
  456.     printf("UMODEM:  %s\n", msg);
  457.     if (LOGFLAG)
  458.     {   fprintf(LOGFP, "UMODEM Fatal Error:  %s\n", msg);
  459.         fclose(LOGFP);
  460.     }
  461.     exit(-1);
  462. }
  463.  
  464. /**  print status (size) of a file  **/
  465. yfile(name)
  466. char *name;
  467. {
  468.     printf("UMODEM File Status Display for %s\n", name);
  469.     if (LOGFLAG) fprintf(LOGFP,"UMODEM File Status Display for %s\n",
  470.       name);
  471.  
  472.     if (open(name,0) < 0)
  473.     {  printf("File %s does not exist\n", name);
  474.        if (LOGFLAG) fprintf(LOGFP,"File %s does not exist\n", name);
  475.        exit(-1);  /* error exit to UNIX */
  476.     }
  477.  
  478.     prfilestat(name);  /* print status */
  479.     printf("\n");
  480.     if (LOGFLAG)
  481.     {  fprintf(LOGFP,"\n");
  482.        fclose(LOGFP);
  483.     }
  484.  
  485.     exit(0);  /* exit to UNIX -- no error */
  486. }
  487.  
  488. /**  receive a file  **/
  489. rfile(name)
  490. char *name;
  491. {
  492.     char mode;
  493.     int fd, j, firstchar, sectnum, sectcurr, tmode;
  494.     int sectcomp, errors, errorflag, recfin;
  495.     register int bufctr, checksum;
  496.     register int c;
  497.     int errorchar, fatalerror, startstx, inchecksum, endetx, endenq;
  498.     long recvsectcnt;
  499.  
  500.     mode = XMITTYPE;  /* set t/b mode */
  501.     if ((fd = creat(name, CREATMODE)) < 0)
  502.           error("Can't create file for receive", FALSE);
  503.     setmodes();  /* setup tty modes for xfer */
  504.     printf("\r\nUMODEM:  File Name: %s", name);
  505.     if (LOGFLAG)
  506.     {    fprintf(LOGFP, "\n----\nUMODEM Receive Function\n");
  507.          fprintf(LOGFP, "File Name: %s\n", name);
  508.          if (FTP1)
  509.             fprintf(LOGFP, "TERM II File Transfer Protocol 1 Selected\n");
  510.          else
  511.         fprintf(LOGFP,
  512.           "TERM II File Transfer Protocol 3 (CP/M UG) Selected\n");
  513.          if (BIT7)
  514.         fprintf(LOGFP, "7-Bit Transmission Enabled\n");
  515.          else
  516.         fprintf(LOGFP, "8-Bit Transmission Enabled\n");
  517.     }
  518.     printf("\r\nUMODEM:  ");
  519.     if (BIT7)
  520.         printf("7-Bit");
  521.     else
  522.         printf("8-Bit");
  523.     printf(" Transmission Enabled");
  524.     printf("\r\nUMODEM:  Ready to RECEIVE File\r\n");
  525.  
  526.     recfin = FALSE;
  527.     sectnum = errors = 0;
  528.     fatalerror = FALSE;  /* NO fatal errors */
  529.     recvsectcnt = 0;  /* number of received sectors */
  530.  
  531.     if (mode == 't')
  532.         tmode = TRUE;
  533.     else
  534.         tmode = FALSE;
  535.  
  536.     if (FTP1)
  537.     {
  538.       while (readbyte(4) != SYN);
  539.       sendbyte(ACK);  /* FTP 1 Sync */
  540.     }
  541.     else sendbyte(NAK);  /* FTP 3 Sync */
  542.  
  543.         do
  544.         {   errorflag = FALSE;
  545.             do {
  546.                   firstchar = readbyte(6);
  547.             } while ((firstchar != SOH) && (firstchar != EOT) && (firstchar 
  548.              != TIMEOUT));
  549.             if (firstchar == TIMEOUT)
  550.         {  if (LOGFLAG)
  551.         fprintf(LOGFP, "Timeout on Sector %d\n", sectnum);
  552.                errorflag = TRUE;
  553.         }
  554.  
  555.             if (firstchar == SOH)
  556.         {  if (FTP1) readbyte(5);  /* discard leading zero */
  557.                sectcurr = readbyte(delay);
  558.                sectcomp = readbyte(delay);
  559.            if (FTP1) startstx = readbyte(delay);  /* get leading STX */
  560.                if ((sectcurr + sectcomp) == BITMASK)
  561.                {  if (sectcurr == (sectnum+1)&BITMASK)
  562.           {  checksum = 0;
  563.              for (j = bufctr = 0; j < BBUFSIZ; j++)
  564.                    {  buff[bufctr] = c = readbyte(delay);
  565.                 checksum = (checksum+c)&BITMASK;
  566.             if (!tmode)  /* binary mode */
  567.             {  bufctr++;
  568.                    continue;
  569.                 }
  570.             if (c == CR)
  571.                continue;  /* skip CR's */
  572.             if (c == CTRLZ)  /* skip CP/M EOF char */
  573.             {  recfin = TRUE;  /* flag EOF */
  574.                    continue;
  575.                 }
  576.                 if (!recfin)
  577.                bufctr++;
  578.              }
  579.              if (FTP1) endetx = readbyte(delay);  /* get ending ETX */
  580.              inchecksum = readbyte(delay);  /* get checksum */
  581.              if (FTP1) endenq = readbyte(delay); /* get ENQ */
  582.              if (checksum == inchecksum)  /* good checksum */
  583.              {  errors = 0;
  584.             recvsectcnt++;
  585.                 sectnum = sectcurr;  /* update sector counter */
  586.             if (write(fd, buff, bufctr) < 0)
  587.                error("File Write Error", TRUE);
  588.                 else
  589.             {  if (FTP1) sendbyte(ESC);  /* FTP 1 requires <ESC> */
  590.                sendbyte(ACK);
  591.             }
  592.              }
  593.              else
  594.              {  if (LOGFLAG)
  595.                 fprintf(LOGFP, "Checksum Error on Sector %d\n",
  596.                 sectnum);
  597.                 errorflag = TRUE;
  598.              }
  599.                   }
  600.                   else
  601.                   { if (sectcurr == sectnum)
  602.                     {  while(readbyte(3) != TIMEOUT);
  603.                if (FTP1) sendbyte(ESC);  /* FTP 1 requires <ESC> */
  604.                        sendbyte(ACK);
  605.                     }
  606.                     else
  607.             {  if (LOGFLAG)
  608.             { fprintf(LOGFP, "Phase Error - Received Sector is ");
  609.               fprintf(LOGFP, "%d while Expected Sector is %d\n",
  610.                sectcurr, (sectnum+1)&BITMASK);
  611.             }
  612.             errorflag = TRUE;
  613.             fatalerror = TRUE;
  614.             if (FTP1) sendbyte(ESC);  /* FTP 1 requires <ESC> */
  615.             sendbyte(CAN);
  616.             }
  617.               }
  618.            }
  619.            else
  620.        {  if (LOGFLAG)
  621.         fprintf(LOGFP, "Header Sector Number Error on Sector %d\n",
  622.            sectnum);
  623.                errorflag = TRUE;
  624.        }
  625.         }
  626.     if (FTP1 && !errorflag)
  627.     {  if (startstx != STX)
  628.        {  errorflag = TRUE;  /* FTP 1 STX missing */
  629.           errorchar = STX;
  630.        }
  631.        if (endetx != ETX)
  632.        {  errorflag = TRUE;  /* FTP 1 ETX missing */
  633.           errorchar = ETX;
  634.        }
  635.        if (endenq != ENQ)
  636.        {  errorflag = TRUE;  /* FTP 1 ENQ missing */
  637.           errorchar = ENQ;
  638.        }
  639.        if (errorflag && LOGFLAG)
  640.        {  fprintf(LOGFP, "Invalid Packet-Control Character:  ");
  641.           switch (errorchar) {
  642.         case STX : fprintf(LOGFP, "STX"); break;
  643.         case ETX : fprintf(LOGFP, "ETX"); break;
  644.         case ENQ : fprintf(LOGFP, "ENQ"); break;
  645.         default  : fprintf(LOGFP, "Error"); break;
  646.           }
  647.           fprintf(LOGFP, "\n");
  648.        }
  649.     }
  650.         if (errorflag == TRUE)
  651.         {  errors++;
  652.        while (readbyte(3) != TIMEOUT);
  653.            sendbyte(NAK);
  654.         }
  655.   }
  656.   while ((firstchar != EOT) && (errors != ERRORMAX) && !fatalerror);
  657.   if ((firstchar == EOT) && (errors < ERRORMAX))
  658.   {  if (!FTP1) sendbyte(ACK);
  659.      close(fd);
  660.      restoremodes(FALSE);  /* restore normal tty modes */
  661.      if (FTP1)
  662.     while (readbyte(3) != TIMEOUT);  /* flush EOT's */
  663.      sleep(3);  /* give other side time to return to terminal mode */
  664.      if (LOGFLAG)
  665.      {  fprintf(LOGFP, "\nReceive Complete\n");
  666.     fprintf(LOGFP,"Number of Received CP/M Records is %ld\n", recvsectcnt);
  667.         fclose(LOGFP);
  668.      }
  669.      printf("\n");
  670.      exit(0);
  671.   }
  672.   else
  673.   {  if (LOGFLAG && FTP1 && fatalerror) fprintf(LOGFP,
  674.     "Synchronization Error");
  675.      error("TIMEOUT -- Too Many Errors", TRUE);
  676.   }
  677. }
  678.  
  679. /**  send a file  **/
  680. sfile(name)
  681. char *name;
  682. {
  683.     char mode;
  684.     int fd, charval, attempts;
  685.     int nlflag, sendfin, tmode;
  686.     register int bufctr, checksum, sectnum;
  687.     char c;
  688.     int sendresp;  /* response char to sent block */
  689.  
  690.     mode = XMITTYPE;  /* set t/b mode */
  691.     if ((fd = open(name, 0)) < 0)
  692.     {  if (LOGFLAG) fprintf(LOGFP, "Can't Open File\n");
  693.             error("Can't open file for send", FALSE);
  694.     }
  695.     setmodes();  /* setup tty modes for xfer */    
  696.     printf("\r\nUMODEM:  File Name: %s", name);
  697.     if (LOGFLAG)
  698.     {   fprintf(LOGFP, "\n----\nUMODEM Send Function\n");
  699.         fprintf(LOGFP, "File Name: %s\n", name);
  700.     }
  701.     prfilestat(name);  /* print file size statistics */
  702.     if (LOGFLAG)
  703.     {  if (FTP1)
  704.         fprintf(LOGFP, "TERM II File Transfer Protocol 1 Selected\n");
  705.        else
  706.         fprintf(LOGFP,
  707.            "TERM II File Transfer Protocol 3 (CP/M UG) Selected\n");
  708.        if (BIT7)
  709.         fprintf(LOGFP, "7-Bit Transmission Enabled\n");
  710.        else
  711.         fprintf(LOGFP, "8-Bit Transmission Enabled\n");
  712.     }
  713.     printf("\r\nUMODEM:  ");
  714.     if (BIT7)
  715.         printf("7-Bit");
  716.     else
  717.         printf("8-Bit");
  718.     printf(" Transmission Enabled");
  719.     printf("\r\nUMODEM:  Ready to SEND File\r\n");
  720.  
  721.     if (mode == 't')
  722.        tmode = TRUE;
  723.     else
  724.        tmode = FALSE;
  725.  
  726.         sendfin = nlflag = FALSE;
  727.       attempts = 0;
  728.  
  729.     if (FTP1)
  730.     {  sendbyte(SYN);  /* FTP 1 Synchronize with Receiver */
  731.        while (readbyte(5) != ACK)
  732.        {  if(++attempts > RETRYMAX*6) error("Remote System Not Responding",
  733.         TRUE);
  734.           sendbyte(SYN);
  735.        }
  736.     }
  737.     else
  738.     {  while (readbyte(30) != NAK)  /* FTP 3 Synchronize with Receiver */
  739.        if (++attempts > RETRYMAX) error("Remote System Not Responding",
  740.         TRUE);
  741.     }
  742.  
  743.     sectnum = 1;  /* first sector number */
  744.     attempts = 0;
  745.  
  746.         do 
  747.     {   for (bufctr=0; bufctr < BBUFSIZ;)
  748.         {   if (nlflag)
  749.             {  buff[bufctr++] = LF;  /* leftover newline */
  750.                nlflag = FALSE;
  751.             }
  752.             if ((charval = read(fd, &c, 1)) < 0)
  753.            error("File Read Error", TRUE);
  754.         if (charval == 0)  /* EOF for read */    
  755.         {  sendfin = TRUE;  /* this is the last sector */
  756.            if (tmode)
  757.               buff[bufctr++] = CTRLZ;  /* Control-Z for CP/M EOF */
  758.                else
  759.               bufctr++;
  760.            continue;
  761.             }
  762.         if (tmode && c == LF)  /* text mode & Unix newline? */
  763.             {  if (c == LF)  /* Unix newline? */
  764.            {  buff[bufctr++] = CR;  /* insert carriage return */
  765.               if (bufctr < BBUFSIZ)
  766.                      buff[bufctr++] = LF;  /* insert Unix newline */
  767.                else
  768.                  nlflag = TRUE;  /* insert newline on next sector */
  769.            }
  770.            continue;
  771.            }    
  772.         buff[bufctr++] = c;  /* copy the char without change */
  773.         }
  774.             attempts = 0;
  775.             do
  776.             {   sendbyte(SOH);  /* send start of packet header */
  777.         if (FTP1) sendbyte(0);  /* FTP 1 Type 0 Packet */
  778.                 sendbyte(sectnum);  /* send current sector number */
  779.                 sendbyte(-sectnum-1);  /* and its complement */
  780.         if (FTP1) sendbyte(STX);  /* send STX */
  781.                 checksum = 0;  /* init checksum */
  782.                 for (bufctr=0; bufctr < BBUFSIZ; bufctr++)
  783.                 {  sendbyte(buff[bufctr]);  /* send the byte */
  784.            if (ARPA && (buff[bufctr]==0xff))  /* ARPA Net FFH esc */
  785.             sendbyte(buff[bufctr]);  /* send 2 FFH's for one */
  786.                    checksum = (checksum+buff[bufctr])&BITMASK;
  787.             }
  788. /*        while (readbyte(3) != TIMEOUT);   flush chars from line */
  789.         if (FTP1) sendbyte(ETX);  /* send ETX */
  790.                 sendbyte(checksum);  /* send the checksum */
  791.         if (FTP1) sendbyte(ENQ);  /* send ENQ */
  792.                 attempts++;
  793.         if (FTP1)
  794.         {  sendresp = NAK;  /* prepare for NAK */
  795.            if (readbyte(10) == ESC) sendresp = readbyte(10);
  796.         }
  797.         else
  798.            sendresp = readbyte(10);  /* get response */
  799.         if ((sendresp != ACK) && LOGFLAG)
  800.            { fprintf(LOGFP, "Non-ACK Received on Sector %d\n",
  801.               sectnum);
  802.              if (sendresp == TIMEOUT)
  803.             fprintf(LOGFP, "This Non-ACK was a TIMEOUT\n");
  804.            }
  805.             }   while((sendresp != ACK) && (attempts != RETRYMAX));
  806.             sectnum++;  /* increment to next sector number */
  807.     }  while (!sendfin && (attempts != RETRYMAX));
  808.  
  809.     if (attempts == RETRYMAX)
  810.     error("Remote System Not Responding", TRUE);
  811.  
  812.     attempts = 0;
  813.     if (FTP1)
  814.     while (attempts++ < 10) sendbyte(EOT);
  815.     else
  816.     {    sendbyte(EOT);  /* send 1st EOT */
  817.     while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX))
  818.        sendbyte(EOT);
  819.     if (attempts >= RETRYMAX)
  820.        error("Remote System Not Responding on Completion", TRUE);
  821.     }
  822.  
  823.     close(fd);
  824.     restoremodes(FALSE);  
  825.     sleep(5);  /* give other side time to return to terminal mode */
  826.     if (LOGFLAG)
  827.     {  fprintf(LOGFP, "\nSend Complete\n");
  828.        fclose(LOGFP);
  829.     }
  830.     printf("\n");
  831.     exit(0);
  832.  
  833. }
  834.  
  835. /*  print file size status information  */
  836. prfilestat(name)
  837. char *name;
  838. {
  839.     struct stat filestatbuf; /* file status info */
  840.  
  841.     stat(name, &filestatbuf);  /* get file status bytes */
  842.     printf("\r\nUMODEM:  Estimated File Size %ldK, %ld Records, %ld Bytes",
  843.       (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
  844.       filestatbuf.st_size);
  845.     if (LOGFLAG)
  846.       fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
  847.       (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
  848.       filestatbuf.st_size);
  849.     return;
  850. }
  851.  
  852. /* get a byte from data stream -- timeout if "seconds" elapses */
  853. readbyte(seconds)
  854. unsigned seconds;
  855. {
  856.     int c;
  857.     
  858.     signal(SIGALRM,alarmfunc);  /* catch alarms */    
  859.     alarm(seconds);  /* set the alarm clock */
  860.     if (read(0, &c, 1) < 0)  /* get a char; error means we timed out */
  861.       {
  862.          return(TIMEOUT);
  863.       }
  864.     alarm(0);  /* turn off the alarm */
  865.     return(c&BITMASK);  /* return the char */
  866. }
  867.  
  868. /* send a byte to data stream */
  869. sendbyte(data)
  870. char data;
  871. {
  872.     char dataout;
  873.     dataout = data&BITMASK;  /* mask for 7 or 8 bits */
  874.     write(1, &dataout, 1);  /* write the byte */
  875.     return;
  876. }
  877.  
  878. /* function for alarm clock timeouts */
  879. alarmfunc()
  880. {
  881.     return;  /* this is basically a dummy function to force error */
  882.          /* status return on the "read" call in "readbyte"    */
  883. }
  884.  
  885. /* print data on TTY setting */
  886. ttyparams()
  887. {
  888.     
  889. /*  Obtain TTY parameters for JHU UNIX  */
  890. #ifdef JHU    
  891.     gtty(0, &ttystemp);  /* get current tty params */
  892. #endif
  893.  
  894. /*  Obtain TTY parameters for Version 7 UNIX  */
  895. #ifdef VER7
  896.     ioctl(0,TIOCGETP,&ttystemp);
  897. #endif
  898.  
  899.     tty = ttyname(0);  /* get name of tty */
  900.     stat(tty, &statbuf);  /* get more tty params */
  901.  
  902.     printf("\r\n\nTTY Device Parameter Display");
  903.       printf("\r\n\tTTY Device Name is %s\r\n\n", tty);
  904.       printf("\tAny Parity Allowed "); pryn(ANYP);
  905.       printf("\tEven Parity Allowed"); pryn(EVENP);
  906.       printf("\tOdd Parity Allowed "); pryn(ODDP);
  907.       printf("\tEcho Enabled       "); pryn(ECHO);
  908.       printf("\tLower Case Map     "); pryn(LCASE);
  909.       printf("\tTabs Expanded      "); pryn(XTABS);
  910.       printf("\tCR Mode Enabled    "); pryn(CRMOD);
  911.       printf("\tRAW Mode Enabled   "); pryn(RAW);
  912.  
  913. /*  Print extended terminal characteristics for JHU UNIX  */
  914. #ifdef JHU
  915.       printf("\tBinary Mode Enabled"); pryn1(NB8);
  916.       printf("\tCR/LF in Col 72    "); pryn1(FOLD);
  917.       printf("\tRecognize ^S/^Q    "); pryn1(STALL);
  918.       printf("\tSend ^S/^Q         "); pryn1(TAPE);
  919.       printf("\tTerminal can BS    "); pryn1(SCOPE);
  920.       printf("\r\n");  /* New line to separate topics */
  921.       printf("\tTerminal Paging is "); pryn1(PAGE);
  922.         if (ttystemp.xflags&PAGE)
  923.         printf("\t  Lines/Page is %d\r\n", ttystemp.xflags&PAGE);
  924.       printf("\r\n");  /* New line to separate topics */
  925.       printf("\tTTY Input Rate     :   ");
  926.         prbaud(ttystemp.ispeed);  /* print baud rate */
  927.       printf("\tTTY Output Rate    :   ");
  928.         prbaud(ttystemp.ospeed);  /* print output baud rate */
  929.       printf("\r\n");  /* New line to separate topics */
  930.       printf("\tMessages Enabled   ");
  931.         if (statbuf.st_mode&011)
  932.            printf(":   Yes\r\n");
  933.         else
  934.            printf(":   No\r\n");
  935. #endif
  936.  
  937. /*  Print extended characteristics for Version 7 UNIX  */
  938. #ifdef VER7
  939.       printf("\tTTY Input Rate     :   ");
  940.         prbaud(ttystemp.sg_ispeed);
  941.       printf("\tTTY Output Rate    :   ");
  942.         prbaud(ttystemp.sg_ospeed);  /* print output baud rate */
  943. #endif
  944.  
  945. }
  946.  
  947. pryn(iflag)
  948. int iflag;
  949. {
  950.  
  951. /*  JHU UNIX flag test  */
  952. #ifdef JHU
  953.     if (ttystemp.mode&iflag)
  954. #endif
  955.  
  956. /*  Version 7 UNIX flag test  */
  957. #ifdef VER7
  958.     if (ttystemp.sg_flags&iflag)
  959. #endif
  960.  
  961.        printf(":   Yes\r\n");
  962.     else
  963.        printf(":   No\r\n");
  964. }
  965.  
  966. /*  Extended flag test for JHU UNIX only  */
  967. #ifdef JHU
  968. pryn1(iflag)
  969. int iflag;
  970. {
  971.     if (ttystemp.xflags&iflag)
  972.        printf(":   Yes\r\n");
  973.     else
  974.        printf(":   No\r\n");
  975. }
  976. #endif
  977.  
  978. prbaud(speed)
  979. char speed;
  980. {
  981.     switch (speed) {
  982.  
  983. /*  JHU UNIX speed flag cases  */
  984. #ifdef JHU        
  985.         case B0050 : printf("50"); break;
  986.         case B0075 : printf("75"); break;
  987.         case B0110 : printf("110"); break;
  988.         case B0134 : printf("134.5"); break;
  989.         case B0150 : printf("150"); break;
  990.         case B0200 : printf("200"); break;
  991.         case B0300 : printf("300"); break;
  992.         case B0600 : printf("600"); break;
  993.         case B1200 : printf("1200"); break;
  994.         case B1800 : printf("1800"); break;
  995.         case B2400 : printf("2400"); break;
  996.         case B4800 : printf("4800"); break;
  997.         case B9600 : printf("9600"); break;
  998.         case EXT_A : printf("External A"); break;
  999.         case EXT_B : printf("External B"); break;
  1000. #endif
  1001.  
  1002. /*  Version 7 UNIX speed flag cases  */
  1003. #ifdef VER7
  1004.         case B50 : printf("50"); break;
  1005.         case B75 : printf("75"); break;
  1006.         case B110 : printf("110"); break;
  1007.         case B134 : printf("134.5"); break;
  1008.         case B150 : printf("150"); break;
  1009.         case B200 : printf("200"); break;
  1010.         case B300 : printf("300"); break;
  1011.         case B600 : printf("600"); break;
  1012.         case B1200 : printf("1200"); break;
  1013.         case B1800 : printf("1800"); break;
  1014.         case B2400 : printf("2400"); break;
  1015.         case B4800 : printf("4800"); break;
  1016.         case B9600 : printf("9600"); break;
  1017.         case EXTA : printf("External A"); break;
  1018.         case EXTB : printf("External B"); break;
  1019. #endif
  1020.  
  1021.         default    : printf("Error"); break;
  1022.     }
  1023.     printf(" Baud\r\n");
  1024. }
  1025.