Full featured xmodem program, v3.4, Part04/03
Steve Grandi
grandi at noao.arizona.edu
Sat Mar 5 08:15:48 AEST 1988
The recent posting of my xmodem program (v13 i093-095) had an incomplete
first shar file. Here are the missing pieces. Also, the second shar seems
to have a hiccup (an extra CR) in the first two lines which results in a
spurious, but harmless, error message.
Steve Grandi, National Optical Astronomy Observatories, Tucson AZ, 602-325-9228
UUCP: {arizona,decvax,hao,ihnp4}!noao!grandi or uunet!noao.arizona.edu!grandi
Internet: grandi at noao.arizona.edu SPAN/HEPNET: 5356::GRANDI or DRACO::GRANDI
***************************************************************************
: This is a shar archive. Extract with sh, not csh.
echo x - xmodem.h
sed -e 's/^X//' > xmodem.h << '!Funky!Stuff!'
X#include <ctype.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sgtty.h>
X#include <signal.h>
X
X/* define macros to print messages in log file */
X#define logit(string) if(LOGFLAG)fprintf(LOGFP,string)
X#define logitarg(string,argument) if(LOGFLAG)fprintf(LOGFP,string,argument)
X
X#define VERSION 34 /* Version Number */
X#define FALSE 0
X#define TRUE 1
X
X
X/* ASCII Constants */
X#define SOH 001
X#define STX 002
X#define ETX 003
X#define EOT 004
X#define ENQ 005
X#define ACK 006
X#define LF 012 /* Unix LF/NL */
X#define CR 015
X#define NAK 025
X#define SYN 026
X#define CAN 030
X#define ESC 033
X
X/* XMODEM Constants */
X#define TIMEOUT -1
X#define ERRORMAX 10 /* maximum errors tolerated while transferring a packet */
X#define WAITFIRST 1 /* seconds between startup characters in read */
X#define STERRORMAX 60 /* maximum "errors" tolerated in read startup */
X#define CRCSWMAX 30 /* maximum time to try CRC mode before switching */
X#define NAKMAX 120 /* maximum times to wait for initial NAK when sending */
X#define RETRYMAX 5 /* maximum retries to be made certain handshaking routines */
X#define KSWMAX 5 /* maximum errors before switching to 128 byte packets */
X#define EOTMAX 10 /* maximum times sender will send an EOT to end transfer */
X#define SLEEPNUM 100 /* target number of characters to collect during sleepy time */
X#define BBUFSIZ 1024 /* buffer size */
X#define NAMSIZ 11 /* length of a CP/M file name string */
X#define CTRLZ 032 /* CP/M EOF for text (usually!) */
X#define CRCCHR 'C' /* CRC request character */
X#define KCHR 'K' /* 1K block request character */
X#define BAD_NAME 'u' /* Bad filename indicator */
X
X#define CREATMODE 0644 /* mode for created files */
X
X/* GLOBAL VARIABLES */
X
Xint ttyspeed; /* tty speed (bits per second) */
Xunsigned char buff[BBUFSIZ]; /* buffer for data */
Xint nbchr; /* number of chars read so far for buffered read */
Xlong filelength; /* length specified in YMODEM header */
Xlong fileread; /* characters actually read so far in file */
Xchar filename[256]; /* place to construct filenames */
XFILE *LOGFP; /* descriptor for LOG file */
X
X/* option flags and state variables */
Xchar XMITTYPE; /* text or binary? */
Xint DEBUG; /* keep debugging info in log? */
Xint RECVFLAG; /* receive? */
Xint SENDFLAG; /* send? */
Xint BATCH; /* batch? (Now used as a state variable) */
Xint CRCMODE; /* CRC or checksums? */
Xint DELFLAG; /* don't delete old log file? */
Xint LOGFLAG; /* keep log? */
Xint LONGPACK; /* do not use long packets on transmit? */
Xint MDM7BAT; /* MODEM7 batch protocol */
Xint YMDMBAT; /* YMODEM batch protocol */
Xint TOOBUSY; /* turn off sleeping in packet read routine */
Xint CHECKLENGTH; /* Are we truncating a file to a YMODEM length? */
X
X
X/* CRC-16 constants. From Usenet contribution by Mark G. Mendel,
X Network Systems Corp. (ihnp4!umn-cs!hyper!mark)
X*/
X
X /* the CRC polynomial. */
X#define P 0x1021
X
X /* number of bits in CRC */
X#define W 16
X
X /* the number of bits per char */
X#define B 8
!Funky!Stuff!
echo x - xmodem.c
sed -e 's/^X//' > xmodem.c << '!Funky!Stuff!'
X/*
X * XMODEM -- Implements the Christensen XMODEM protocol,
X * for packetized file up/downloading.
X *
X * I have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty
X * structures, gettimeofday system call, etc.) in the source file
X * getput.c; but I make no guarantees. Also, I have made no attempt to
X * keep variable names under 7 characters (although a cursory check
X * shows that all variables are unique within 7 first characters).
X * See the README file for some notes on SYS V adaptations.
X * The program has been successfully run on VAXes (4.3BSD) and SUN-3s
X * (2.x/3.x) against MEX-PC and ZCOMM/DSZ.
X *
X * -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
X *
X * XMODEM Version 1.0 - by Brian Kantor, UCSD (3/84)
X *
X * Version 2.0 (CRC-16 and Modem7 batch file transfer) -- Steve Grandi, NOAO (5/85)
X *
X * Version 2.1 (1K packets) -- Steve Grandi, NOAO (7/85)
X *
X * Version 2.2 (general clean-ups and multi-character read speed-ups) -- Steve Grandi, NOAO (9/85)
X *
X * Version 2.3 (napping while reading packet; split into several source files) -- Steve Grandi, NOAO (1/86)
X *
X * Version 3.0 (Ymodem batch receive; associated changes) -- Steve Grandi, NOAO (2/86)
X *
X * Version 3.1 (Ymodem batch send; associated changes) -- Steve Grandi, NOAO (8/86)
X *
X * Version 3.2 (general cleanups) -- Steve Grandi, NOAO (9/86)
X *
X * Released to the world (1/87)
X *
X * Version 3.3 (see update.doc) -- Steve Grandi, NOAO (5/87)
X *
X * Version 3.4 (see update.doc) -- Steve Grandi, NOAO (10/87)
X *
X * Released to the world (1/88)
X *
X * Please send bug fixes, additions and comments to:
X * {ihnp4,hao}!noao!grandi grandi at noao.arizona.edu
X */
X
X#include "xmodem.h"
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X char *getenv();
X FILE *fopen();
X char *unix_cpm();
X char *strcpy();
X char *strcat();
X
X char *fname = filename; /* convenient place to stash file names */
X char *logfile = "xmodem.log"; /* Name of LOG File */
X
X char *stamptime(); /* for timestamp */
X
X char *defname = "xmodem.in"; /* default file name if none given */
X
X struct stat filestatbuf; /* file status info */
X
X int index;
X char flag;
X long expsect;
X
X /* initialize option flags */
X
X XMITTYPE = 't'; /* assume text transfer */
X DEBUG = FALSE; /* keep debugging info in log */
X RECVFLAG = FALSE; /* not receive */
X SENDFLAG = FALSE; /* not send either */
X BATCH = FALSE; /* nor batch */
X CRCMODE = FALSE; /* use checksums for now */
X DELFLAG = FALSE; /* don't delete old log file */
X LOGFLAG = TRUE; /* keep log */
X LONGPACK = FALSE; /* do not use long packets on transmit */
X MDM7BAT = FALSE; /* no MODEM7 batch mode */
X YMDMBAT = FALSE; /* no YMODEM batch mode */
X TOOBUSY = FALSE; /* not too busy for sleeping in packet read */
X
X printf("XMODEM Version %d.%d", VERSION/10, VERSION%10);
X printf(" -- UNIX-Microcomputer Remote File Transfer Facility\n");
X
X if (argc == 1)
X {
X help();
X exit(-1);
X }
X
X index = 0; /* set index for flag loop */
X
X while ((flag = argv[1][index++]) != '\0')
X switch (flag) {
X case '-' : break;
X case 'X' :
X case 'x' : DEBUG = TRUE; /* turn on debugging log */
X break;
X case 'C' :
X case 'c' : CRCMODE = TRUE; /* enable CRC on receive */
X break;
X case 'D' :
X case 'd' : DELFLAG = TRUE; /* delete log file */
X break;
X case 'L' :
X case 'l' : LOGFLAG = FALSE; /* turn off log */
X break;
X case 'm' :
X case 'M' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */
X BATCH = TRUE;
X break;
X case 'y' :
X case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */
X BATCH = TRUE;
X break;
X case 'k' :
X case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */
X break;
X case 't' :
X case 'T' : TOOBUSY = TRUE; /* turn off sleeping */
X break;
X case 'R' :
X case 'r' : RECVFLAG = TRUE; /* receive file */
X XMITTYPE = gettype(argv[1][index++]); /* get t/b */
X break;
X case 'S' :
X case 's' : SENDFLAG = TRUE; /* send file */
X XMITTYPE = gettype(argv[1][index++]);
X break;
X default : printf ("Invalid Flag %c ignored\n", flag);
X break;
X }
X
X if (DEBUG)
X LOGFLAG = TRUE;
X
X if (LOGFLAG)
X {
X if ((fname = getenv("HOME")) == 0) /* Get HOME variable */
X error("Fatal - Can't get Environment!", FALSE);
X fname = strcat(fname, "/");
X fname = strcat(fname, logfile);
X if (!DELFLAG)
X LOGFP = fopen(fname, "a"); /* append to LOG file */
X else
X LOGFP = fopen(fname, "w"); /* new LOG file */
X if (!LOGFP)
X error("Fatal - Can't Open Log File", FALSE);
X
X fprintf(LOGFP,"\n++++++++ %s", stamptime());
X fprintf(LOGFP,"XMODEM Version %d.%d\n", VERSION/10, VERSION%10);
X fprintf(LOGFP,"Command line: %s %s", argv[0], argv[1]);
X for (index=2; index<argc; ++index)
X fprintf(LOGFP, " %s", argv[index]);
X fprintf(LOGFP, "\n");
X }
X
X getspeed(); /* get tty-speed for time estimates */
X
X if (RECVFLAG && SENDFLAG)
X error("Fatal - Both Send and Receive Functions Specified", FALSE);
X
X if (MDM7BAT && YMDMBAT)
X error("Fatal - Both YMODEM and MODEM7 Batch Protocols Specified", FALSE);
X
X if (!RECVFLAG && !SENDFLAG)
X error("Fatal - Either Send or Receive Function must be chosen!",FALSE);
X
X if (SENDFLAG && argc==2)
X error("Fatal - No file specified to send",FALSE);
X
X if (RECVFLAG && argc==2)
X {
X /* assume we really want CRC-16 in batch, unless we specify MODEM7 mode */
X CRCMODE = MDM7BAT ? FALSE : TRUE;
X printf("Ready for BATCH RECEIVE");
X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X printf("Send several Control-X characters to cancel\n");
X logit("Batch Receive Started");
X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X strcpy(fname, defname);
X }
X
X if (RECVFLAG && argc>2)
X {
X if(open(argv[2], 0) != -1) /* check for overwriting */
X {
X logit("Warning -- Target File Exists and is Being Overwritten\n");
X printf("Warning -- Target File Exists and is Being Overwritten\n");
X }
X printf("Ready to RECEIVE File %s", argv[2]);
X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X printf("Send several Control-X characters to cancel\n");
X logitarg("Receiving in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X strcpy(fname,argv[2]);
X }
X
X if (RECVFLAG)
X {
X setmodes(); /* set tty modes for transfer */
X
X while(rfile(fname) != FALSE); /* receive files */
X
X restoremodes(FALSE); /* restore normal tty modes */
X
X sleep(2); /* give other side time to return to terminal mode */
X exit(0);
X }
X
X if (SENDFLAG && BATCH)
X {
X if (YMDMBAT)
X {
X printf("Ready to YMODEM BATCH SEND");
X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X logit("YMODEM Batch Send Started");
X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X }
X else if (MDM7BAT)
X {
X printf("Ready to MODEM7 BATCH SEND");
X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X logit("MODEM7 Batch Send Started");
X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X }
X printf("Send several Control-X characters to cancel\n");
X
X setmodes();
X for (index=2; index<argc; index++) {
X if (stat(argv[index], &filestatbuf) < 0) {
X logitarg("\nFile %s not found\n", argv[index]);
X continue;
X }
X sfile(argv[index]);
X }
X sfile("");
X restoremodes(FALSE);
X
X logit("Batch Send Complete\n");
X sleep(2);
X exit (0);
X }
X
X if (SENDFLAG && !BATCH)
X {
X if (stat(argv[2], &filestatbuf) < 0)
X error("Can't find requested file", FALSE);
X expsect = (filestatbuf.st_size/128)+1;
X
X printf("File %s Ready to SEND", argv[2]);
X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X printf("Estimated File Size %ldK, %ld Sectors, %ld Bytes\n",
X (filestatbuf.st_size/1024)+1, expsect,
X filestatbuf.st_size);
X projtime(expsect, stdout);
X printf("Send several Control-X characters to cancel\n");
X logitarg("Sending in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
X
X setmodes();
X sfile(argv[2]);
X restoremodes(FALSE);
X
X sleep(2);
X exit(0);
X }
X}
!Funky!Stuff!
echo x - batch.c
sed -e 's/^X//' > batch.c << '!Funky!Stuff!'
X/*
X * Various routines for batch tranfer
X */
X
X#include "xmodem.h"
X
X/* make sure filename sent or received in YMODEM batch is canonical.
X * Turn Unix '/' into CP/M ':' and translate to all lower case.
X * Remove trailing dot in incoming name.
X */
X
Xunixify (name)
Xchar *name;
X {
X char *ptr;
X for (ptr=name; *ptr; ++ptr)
X {
X if (*ptr == '/')
X *ptr = ':';
X if (isupper (*ptr))
X *ptr |= 040;
X }
X ptr--;
X if (*ptr == '.')
X *ptr = '\0';
X }
X
Xcpmify (name)
Xchar *name;
X {
X char *ptr;
X for (ptr=name; *ptr; ++ptr)
X {
X if (*ptr == ':')
X *ptr = '/';
X if (isupper (*ptr))
X *ptr |= 040;
X }
X }
X
X
X/* convert a CP/M file name received in a MODEM7 batch transfer
X * into a unix file name mapping '/' into ':', converting to all
X * upper case and adding dot in proper place.
X * Use "filename" to hold name.
X * Code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *cpm_unix (string)
Xunsigned char *string;
X{
X register int i;
X unsigned char *iptr, temp;
X register char *optr;
X
X if (*string == '\0')
X error("Null file name in MODEM7 batch receive", TRUE);
X
X for (iptr=string; (temp = *iptr) ; ) {
X temp &= 0177; /* strips bit 7 */
X if (isupper(temp))
X temp |= 040; /* set bit 5 for lower case */
X if (temp == '/')
X temp=':'; /* map / into : */
X *iptr++ = temp;
X }
X
X /* put in main part of name */
X iptr=string;
X optr=filename;
X for (i=0; i<8; i++) {
X if (*iptr != ' ')
X *optr++ = *iptr++;
X }
X
X /* add dot if necessary */
X if (string[8] != ' ' || string[9] != ' ' || string[10] != ' ')
X *optr++ = '.';
X
X /* put in extension */
X iptr = &string[8];
X for (i=0; i<3; i++) {
X if (*iptr != ' ')
X *optr++ = *iptr++;
X }
X
X *optr++ = '\000';
X return (filename);
X}
X
X/* Send 11 character CP/M filename for MODEM7 batch transmission
X * Returns -1 for a protocol error; 0 if successful
X * NOTE: we tromp a little on the argument string!
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xsend_name(name)
Xchar *name;
X{
X register int cksum;
X register char *ptr;
X
X xmdebug("send_name");
X
X /* append cp/m EOF */
X name[NAMSIZ] = CTRLZ;
X name[NAMSIZ+1] = '\000';
X
X /* create checksum */
X ptr = name;
X cksum = 0;
X while (*ptr)
X cksum += *ptr++;
X cksum &= 0x00FF;
X
X /* send filename */
X
X sendbyte(ACK);
X ptr = name;
X sendbyte(*ptr++);
X
X while (*ptr) {
X
X switch (readbyte(15)) {
X
X case ACK: break;
X
X case TIMEOUT: {
X logit("Timeout while sending MODEM7 filename\n");
X sendbyte(BAD_NAME);
X return (-1);
X }
X
X default: {
X logit("Error while sending MODEM7 filename\n");
X sendbyte(BAD_NAME);
X return (-1);
X }
X }
X
X sendbyte (*ptr++);
X }
X
X /* Check checksum returned by other side against my value */
X if (readbyte(16) != cksum) {
X logit("Bad checksum while sending MODEM7 filename\n");
X sendbyte(BAD_NAME);
X return (-1);
X }
X
X sendbyte(ACK);
X return (0);
X}
X
X/* Convert Unix filename to 11 character CP/M file name (8 char name,
X * 3 char extension, dot in between is not included).
X * map ':' into '/'; Use filename to hold name.
X * code stolen from D. Thompson's (IRTF) xmodem.c
X */
X
Xchar *unix_cpm(string)
Xchar *string;
X{
X register char *iptr, *optr, temp;
X int i;
X
X char *rindex();
X char *strcpy();
X
X /* blank 11 character name */
X (void) strcpy (filename," ");
X
X /* strip off any path name */
X if ((iptr = rindex(string,'/')))
X iptr++;
X else
X iptr=string;
X
X /* skip leading '.'s */
X while (*iptr == '.')
X iptr++;
X
X /* copy main part of name */
X optr = filename;
X i = 8;
X while ((i--) && (*iptr) && (*iptr != '.'))
X *optr++ = *iptr++;
X
X /* advance to unix extension, or end of unix name */
X while ((*iptr != '.') && (*iptr))
X iptr++;
X
X /* skip over the '.' */
X while (*iptr == '.')
X iptr++;
X
X /* copy extension */
X optr = &filename[8];
X i=3;
X while ((i--) && (*iptr) && (*iptr != '.'))
X *optr++ = *iptr++;
X
X filename[NAMSIZ] = '\000';
X
X /* Fuss with name */
X for (iptr=filename; (temp = *iptr) ;) {
X temp &= 0177; /* strip bit 7 (parity bit) */
X if (islower(temp))
X temp &= ~040; /* make upper case */
X if (temp == ':')
X temp ='/'; /* map ':' into '/' */
X *iptr++ = temp;
X }
X
X if (DEBUG)
X fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
X
X return(filename);
X}
!Funky!Stuff!
exit
--
Steve Grandi, National Optical Astronomy Observatories, Tucson AZ, 602-325-9228
UUCP: {arizona,decvax,hao,ihnp4}!noao!grandi or uunet!noao.arizona.edu!grandi
Internet: grandi at noao.arizona.edu SPAN/HEPNET: 5356::GRANDI or DRACO::GRANDI
More information about the Comp.sources.bugs
mailing list