home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
-
- /*
- * rtmodem.c -- This program allows the RT-11 user to transfer files to
- * and from a host system (usually CP/M) using Ward Christensen's
- * MODEM/XMODEM protocol. No terminal emulation is provided (yet).
- * Written in DECUS C by:
- *
- * Robert B. Hoffman, N3CVL 5-Mar-82
- * <Hoffman%Pitt.csnet@CSNet-Relay.ARPA>
- * {allegra, bellcore, cadre, idis, psuvax1}!pitt!hoffman
- *
- * 5-Mar-82 Original Version
- *
- * 18-Mar-83 Changed transmit routine to wait for one of (ACK,NAK,CAN,
- * or TIMEOUT) before re-sending the sector. Garbage chars are
- * now ignored. Changed receive routine to print a count of
- * bytes transferred.
- *
- * 26-Aug-83 Changed transmit routine to print a count of bytes
- * transferred. Changed receive routine to cancel transfer if
- * the allocated file size is exceeded. *** Note: This is
- * bogus -- putc() isn't returning any error condition. (see below)
- *
- * 9-Dec-83 Changed receive routine to send NAKs only after it times
- * out waiting for a SOH, rather than NAKing every non-SOH.
- *
- * 13-Feb-84 Changed buffer array from char to ints. It seems that when
- * putc was called with a char with the eighth bit set, then
- * it was returning a negative int, which appeared as an error.
- * If putc is called with an int, it works just fine, and returns
- * the expected error condition not found above. Also changed
- * command structure to make it quicker. Now, when a transfer
- * completes, it returns to command mode rather than exiting.
- *
- * 19-Feb-84 Changed the 'bytes transmitted' message to indicate sectors,
- * blocks, and bytes. Added bell chars to termination messages.
- *
- * 15-Aug-84 Fixed a bug that allowed nulls to be transmitted in text mode
- * and appended an extra sector's worth of nulls in binary mode.
- * Also changed command scanner to add Ethernet escape option
- * and to make it easier to add more options. Added Ethernet
- * escapes to output driver.
- */
-
- struct device {
- int rcsr;
- int rbuf;
- int xcsr;
- int xbuf;
- };
-
- #define SOH 01
- #define EOT 04
- #define ACK 06
- #define NAK 025
- #define CAN 030
- #define TIMEOUT -1
- #define TRUE 1
- #define FALSE 0
- #define EVER ;;
-
- int $$narg = 1;
-
- struct device *dladdr = 0176500;
-
- int buf[128];
- int ether;
- FILE *file;
-
- main() {
- register int i, c;
- register char *p;
- char blkno, cblkno, *filnam, cmdlin[40];
- int bcnt, cksm, ok, nakcount, sndrcv, txtbin;
- long nbytes;
-
- printf("RTMODEM -- RT-11 file transfer program\n\n");
-
- cmd:
- do {
- printf("RTMODEM command=> ");
- gets(cmdlin);
- for (i=0; i<strlen(cmdlin); i++)
- cmdlin[i] = (isupper(cmdlin[i]) ? tolower(cmdlin[i]) : cmdlin[i]);
- filnam = index(cmdlin,' ');
- *filnam++ = 0; /* this is sneaky -- it null-terminates the */
- /* command part of the string and makes */
- /* filnam point to the file name */
-
- ok = TRUE; /* assume cmd will be OK */
- p = index(cmdlin,'s'); /* sending */
- if (p == NULL) {
- p = index(cmdlin,'r'); /* receiving */
- }
- if (p == NULL) {
- ok = FALSE; /* one of these MUST be present */
- }
- sndrcv = *p;
-
- p = index(cmdlin,'t'); /* text */
- if (p == NULL) {
- p = index(cmdlin,'b'); /* binary */
- }
- if (p == NULL) {
- ok = FALSE; /* one of these must also be present */
- }
- txtbin = *p;
-
- if (index(cmdlin,'e') == NULL) { /* ethernet mode */
- ether = FALSE;
- } else {
- ether = TRUE;
- }
-
- if (!ok) {
- printf("\nCommands are of the form:\n");
- printf(" rt|rb|st|sb [e] filename\n");
- printf(" rt -- receive text\n");
- printf(" rb -- receive binary\n");
- printf(" st -- send text\n");
- printf(" sb -- send binary\n");
- printf(" e -- use Ethernet escape\n\n");
- }
- } while (!ok);
-
- freopen("tt:", "wu", stdout);
- if (ether) {
- printf("Using Ethernet character escape.\n");
- }
- if (sndrcv == 's') {
- printf("Sending file %s, %s mode.\n", filnam,
- (txtbin == 't' ? "text" : "binary"));
- if ((file = fopen(filnam,"rn")) == NULL) {
- fprintf(stderr,"Couldn't open input file %s.\n",
- filnam);
- goto cmd;
- }
- printf("File open, ready to send.\n");
- nbytes = 512L * (long)(file->io_size);
- printf("File is %d sectors (%ld bytes) long.\n",
- (file->io_size) * 4, nbytes);
- nbytes /= 84L; /* 120 cps * 70% = 84 cps effective */
- printf("Estimated transfer time: %ld min, %ld sec at 1200 bps.\n",
- nbytes/60L, nbytes%60L);
-
- while ((c = getmod()) != NAK)
- ;
-
- nbytes = 0L;
- blkno = 0;
- do {
- i = 0;
- do {
- c = getc(file);
- if (c == EOF) {
- if (i == 0)
- goto sfin;
- if (txtbin == 't')
- buf[i++] = 032;
- else
- buf[i++] = 0;
- }
- else if (txtbin != 't' || c != 0) {
- buf[i++] = c;
- }
- } while (i < 128);
- blkno++;
- do {
- outmod(SOH);
- outmod(blkno);
- outmod(~blkno);
- cksm = 0;
- for (bcnt = 0; bcnt < 128; bcnt++) {
- outmod(buf[bcnt]);
- cksm = (cksm + buf[bcnt]) % 256;
- }
- outmod(cksm);
- do {
- ok = TRUE; /* Assume all OK */
- c = getmod();
- switch (c) {
- case ACK:
- case NAK:
- case CAN:
- case TIMEOUT:
- break;
-
- default:
- ok = FALSE;
- break;
- }
- } while (!ok);
- } while (c != ACK && c != CAN);
-
- nbytes += 128L;
- printf("%ld sec, %ld blk, %ld b\r", nbytes/128L,
- (nbytes+384L)/512L, nbytes);
-
- if (c == CAN) {
- fclose(file);
- printf("\n\007\007\007Transfer cancelled by host.\n");
- goto cmd;
- }
-
- } while (c == ACK && !feof(file));
-
- sfin:
- outmod(EOT);
- c = getmod();
- if (c == ACK)
- printf("\n\007\007\007File transmitted\n");
- else
- printf("\n\007\007\007Final ACK was 0%o instead!\n",c);
-
- fclose(file);
- goto cmd;
- }
- else {
- printf("Receiving file %s, %s mode.\n", filnam,
- (txtbin == 't' ? "text" : "binary"));
- if ((file = fopen(filnam,"wn")) == NULL) {
- fprintf(stderr,"Couldn't open output file %s\n",
- filnam);
- goto cmd;
- }
- printf("File open, ready to receive.\n");
-
- nbytes = 0L;
- outmod(NAK); /* Send initial NAK */
- nakcount = 0;
- for (EVER) {
- do {
- c = getmod();
- switch (c) {
- case TIMEOUT:
- outmod(NAK);
- nakcount++;
- break;
-
- case EOT:
- goto rfin;
-
- default:
- break;
- }
- } while (c != SOH);
-
- blkno = getmod();
- cblkno = getmod();
- cksm = 0;
- for (i=0; i<128; i++) {
- c = buf[i] = getmod();
- cksm = (cksm + c) % 256;
- }
- c = getmod();
- ok = (((SOH+blkno+cblkno) % 256) == 0 && cksm == c);
- if (ok) {
- for (i=0; i<128; i++) {
- if (buf[i] == '\032' && txtbin == 't')
- break;
- c = putc(buf[i],file);
- if (c == EOF) {
- outmod(CAN);
- fclose(file);
- printf("\n\07Disk full! Transfer cancelled.\n");
- goto cmd;
- }
- }
- nbytes += 128L;
- printf("%ld sec, %ld blk, %ld b\r",
- nbytes/128L, (nbytes+384L)/512L,
- nbytes);
- outmod(ACK);
- nakcount = 0;
- } else {
- if (nakcount > 10) {
- printf("\nR)etry or Q)uit=> ");
- gets(cmdlin);
- c = cmdlin[0];
- if (c == 'q' || c == 'Q') {
- outmod(CAN);
- fclose(file);
- goto cmd;
- }
- nakcount = 0;
- }
- nakcount++;
- printf("\nNAK %d\n", nakcount);
- outmod(NAK);
- }
- }
- rfin:
- fclose(file);
- outmod(ACK);
- printf("\n\007\007\007Transfer complete\n");
- goto cmd;
- }
- }
-
- /*
- * get a character from the modem. A 10 second timeout is
- * needed to preclude hanging the modem if one side should
- * terminate abnormally. The constant of 160000 provides this
- * delay for an LSI-11.
- */
-
- getmod() {
- register struct device *MODEM;
- long n;
-
- MODEM = dladdr;
- for (n=160000L; ((MODEM->rcsr & 0200) == 0) && (n > 0L); n--)
- ;
- if (n == 0L) {
- printf("\nTimeout!\n");
- return(-1);
- }
- return((MODEM->rbuf) & 0377);
- }
-
- /*
- * Send a character to the modem.
- */
-
- outmod(c)
- char c;
- {
- if (ether) {
- switch(c) {
- case 020:
- case 021:
- case 023:
- outm(020);
- break;
- default:
- break;
- }
- }
- outm(c);
- }
-
- outm(c)
- char c;
- {
- register struct device *MODEM;
-
- MODEM = dladdr;
- while ((MODEM->xcsr & 0200) == 0)
- ;
- MODEM->xbuf = c;
- }
-