v07i093: Full-featured XMODEM, Part02/02

sources-request at mirror.TMC.COM sources-request at mirror.TMC.COM
Tue Jan 20 00:10:17 AEST 1987


Submitted by: seismo!noao!grandi (Steve Grandi)
Mod.sources: Volume 7, Issue 93
Archive-name: xmodem/Part02

[  I'll be at USENIX, if you want to come look for me with bats and clubs.
	--r$  ]

: This is a shar archive.  Extract with sh, not csh.
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
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	}
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 */
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
Xchecknak:		switch (readbyte(6)) {
X
X			case CAN: {
X				if (readbyte(3) == CAN)
X					error("Program Canceled by User",TRUE);
X				else
X					goto checknak;
X			}
X
X			case ACK: break;
X
X			case TIMEOUT: {
X				logit("Timeout while sending filename\n");
X				sendbyte(BAD_NAME);
X				return (-1);
X			}
X
X			default: {
X				logit("Error while sending 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(10) != cksum) {
X		logit("Bad checksum while sending 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!
echo x - misc.c
sed -e 's/^X//' > misc.c << '!Funky!Stuff!'
X#include "xmodem.h"
X
X/*  Print Help Message  */
Xhelp()
X	{
X	printf("\nUsage:  \n\txmodem ");
X	printf("-[rb!rt!sb!st][options] filename\n");
X	printf("\nMajor Commands --");
X	printf("\n\trb <-- Receive Binary");
X	printf("\n\trt <-- Receive Text");
X	printf("\n\tsb <-- Send Binary");
X	printf("\n\tst <-- Send Text");
X	printf("\nOptions --");
X	printf("\n\tY  <-- Use YMODEM Batch Mode on transmit");
X	printf("\n\tB  <-- Use MODEM7 Batch Mode on transmit");
X	printf("\n\tK  <-- Use 1K packets on transmit");
X	printf("\n\tc  <-- Select CRC mode on receive");
X	printf("\n\td  <-- Delete xmodem.log file before starting");
X	printf("\n\tl  <-- (ell) Turn OFF Log File Entries");
X	printf("\n\tx  <-- Include copious debugging information in log file");
X	printf("\n");
X	}
X
X/* get type of transmission requested (text or binary) */
Xgettype(ichar)
Xchar ichar;
X	{
X	if (ichar == 't') return(ichar);
X	if (ichar == 'b') return(ichar);
X	error("Invalid Send/Receive Parameter - not t or b", FALSE);
X	return(0);
X	}
X
X/* print error message and exit; if mode == TRUE, restore normal tty modes */
Xerror(msg, mode)
Xchar *msg;
Xint mode;
X	{
X	if (mode)
X		restoremodes(TRUE);  /* put back normal tty modes */
X	printf("\r\n%s\n", msg);
X	if ((LOGFLAG || DEBUG) && (LOGFP != NULL))
X		{   
X		fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
X	    	fclose(LOGFP);
X		}
X	exit(-1);
X	}
X
X
X/* Construct a proper (i.e. pretty) sector count for messages */
X
Xchar
X*sectdisp(recvsectcnt, bufsize, plus1)
Xlong recvsectcnt;
Xint bufsize, plus1;
X	{
X	static char string[20];
X	if (plus1)
X		recvsectcnt += (bufsize == 128) ? 1 : 8;
X	if (bufsize == 128 || recvsectcnt == 0)
X		sprintf (string, "%d", recvsectcnt);
X	else
X		sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
X	return(string);
X	}
X
X/* type out debugging info */
Xxmdebug(str)
Xchar *str;
X	{
X	if (DEBUG && (LOGFP != NULL))
X		fprintf(LOGFP,"DEBUG: '%s'\n",str);
X	}
X
X/* print elapsed time and rate of transfer in logfile */
X
Xint quant[] = { 60, 60, 24};	
Xchar *sep[] = { "second", "minute", "hour" };
X
Xprtime (numsect, seconds)
Xlong numsect;
Xtime_t seconds;
X
X{
X	register int i;
X	register int Seconds;
X	int nums[3];
X	int rate = 0;
X
X	if (!LOGFLAG)
X		return(0);
X
X	Seconds = (int)seconds;
X
X	if (Seconds != 0)
X		rate = 128 * numsect/Seconds;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (Seconds % quant[i]);
X		Seconds /= quant[i];
X	}
X
X	fprintf (LOGFP, "%ld CP/M Sectors Transfered in ", numsect);
X	while (--i >= 0)
X		if (nums[i])
X			fprintf (LOGFP, "%d %s%c ", nums[i], sep[i],
X				nums[i] == 1 ? '\0' : 's');
X	fprintf (LOGFP, "\n");
X
X	if (rate != 0)
X		fprintf (LOGFP, "Transfer Rate = %d Characters per Second\n", rate);
X
X	return(0);
X}
X
X/* Print elapsed time estimate */
X
Xprojtime (numsect, fd)
Xlong numsect;
XFILE *fd;
X	{
X	register int i;
X	register int seconds;
X	int nums[3];
X
X	if (numsect == 0)
X		return (0);
X
X/* constant below should really be 1280; reduced to 90% to account for time lost in overhead */
X
X	seconds = 1422 * numsect / ttyspeed + 1;
X
X	for (i=0; i<3; i++) {
X		nums[i] = (seconds % quant[i]);
X		seconds /= quant[i];
X	}
X
X	fprintf (fd, "Estimated transmission time ");
X	while (--i >= 0)
X		if (nums[i])
X			fprintf (fd, "%d %s%c ", nums[i], sep[i],
X				nums[i] == 1 ? '\0' : 's');
X	fprintf (fd, "\n");
X	return (0);
X	}
!Funky!Stuff!
echo x - receive.c
sed -e 's/^X//' > receive.c << '!Funky!Stuff!'
X#include "xmodem.h"
X
X/**  receive a file  **/
X
X/* returns TRUE if in the midst of a batch transfer */
X/* returns FALSE if no more files are coming */
X
X/* This routine is one HUGE do-while loop with far to many indented levels.
X * I chose this route to facilitate error processing and to avoid GOTOs.
X * Given the troubles I've had keeping the nested IF statements straight,
X * I was probably mistaken...
X */
X
Xrfile(name)
Xchar *name;
X    {
X
X    char *sectdisp();
X    char *cpm_unix();
X    char *strcpy();
X    time_t time();
X
X    int fd,     /* file descriptor for created file */
X    checksum,   /* packet checksum */
X    firstchar,  /* first character of a packet */
X    sectnum,    /* number of last received packet (modulo 128) */
X    sectcurr,   /* second byte of packet--should be packet number (mod 128) */
X    sectcomp,   /* third byte of packet--should be complement of sectcurr */
X    tmode,      /* text mode if true, binary mode if false */
X    errors,     /* running count of errors (reset when 1st packet starts */
X    errorflag,  /* set true when packet (or first char of putative packet) is invalid */
X    fatalerror, /* set within main "read-packet" Do-While when bad error found */
X    inchecksum, /* incoming checksum or CRC */
X    expsect,    /* expected number of sectors (YMODEM batch) */
X    bufsize;    /* packet size (128 or 1024) */
X    long recvsectcnt;   /* running sector count (128 byte sectors) */
X    int bufctr; /* number of real chars in read packet */
X    unsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
X    time_t start;   /* starting time of transfer */
X    int openflag = FALSE;   /* is file open for writing? */
X
X    logit("----\nXMODEM File Receive Function\n");
X    if (CRCMODE)
X        logit("CRC mode requested\n");
X
X    BATCH = FALSE;          /* don't know if really are in batch mode ! */
X    fatalerror = FALSE;
X    sectnum = errors = recvsectcnt = 0;
X    bufsize = 128;
X
X    tmode = (XMITTYPE == 't') ? TRUE : FALSE;
X
X    sleep(1);       /* wait a second for other side to get ready */
X    if (CRCMODE)        /* start up transfer */
X        sendbyte(CRCCHR);
X    else
X        sendbyte(NAK);
X
X
X    do                  /* start of MAIN Do-While loop to read packets */
X        {   
X        errorflag = FALSE;
X        do              /* start by reading first byte in packet */
X            {
X            firstchar = readbyte(6);
X            } 
X            while ((firstchar != SOH) 
X                && (firstchar != STX) 
X                && (firstchar != EOT) 
X                && (firstchar != ACK || recvsectcnt > 0) 
X                && (firstchar != TIMEOUT) 
X                && (firstchar != CAN));
X
X        if (firstchar == EOT)           /* check for REAL EOT */
X            {
X            if (readbyte(1) != TIMEOUT)
X                {
X                firstchar = TIMEOUT;
X                errorflag = TRUE;
X                logit ("EOT followed by characters; ignored\n");
X                }
X            }
X
X        if (firstchar == TIMEOUT)       /* timeout? */
X            {  
X            logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
X                errorflag = TRUE;
X            }
X
X        if (firstchar == CAN)           /* bailing out? */
X            {
X            if ((readbyte(3) & 0x7f) == CAN)
X                error("Reception canceled at user's request",TRUE);
X            else
X                {
X                errorflag = TRUE;
X                logit("Received single CAN character\n");
X                }
X            }
X
X        if (firstchar == ACK)           /* MODEM7 batch? */
X            {
X            int i,c; 
X
X            logit("MODEM7 Batch Protocol\n");
X            nameptr = buff;
X            checksum = 0;
X
X            for (i=0; i<NAMSIZ; i++)
X                {
X                c = readbyte(3);
X
X                if (c == CAN)
X                    {
X                    if (readbyte(3) == CAN)
X                        error("Program Canceled by User", TRUE);
X                    else
X                        {
X                        logit("Received single CAN character\n");
X                        errorflag = TRUE;
X                        break;
X                        }
X                    }
X
X                if (c == EOT && i == 0)
X                    {
X                    logit("MODEM7 Batch Receive Complete\n");
X                    return (FALSE);
X                    }
X
X                if (c == TIMEOUT)
X                    {
X                    logit("Timeout waiting for MODEM7 filename character\n");
X                    errorflag = TRUE;
X                    break;
X                    }
X
X                if (c == BAD_NAME)
X                    {
X                    logit("Error during MODEM7 filename transfer\n");
X                    errorflag = TRUE;
X                    break;
X                    }
X
X                *nameptr++ = c;
X                checksum += c;
X                sendbyte(ACK);
X                }
X
X            if (!errorflag)
X                {
X                c = readbyte(3);
X                if (c == CTRLZ)     /* OK; end of string found */
X                    {
X                    sendbyte(checksum + CTRLZ);
X                    if (readbyte(3) == ACK)     /* file name found! */
X                        {
X                        xmdebug("MODEM7 file name OK");
X                        *nameptr = '\000';
X                        name = cpm_unix(buff);
X                        BATCH = TRUE;
X                        }
X                    else
X                        {
X                        logit("Checksum error in MODEM7 filename\n");
X                        errorflag = TRUE;
X                        }
X                    }
X                else
X                    {
X                    logit("Length error in MODEM7 fielname\n");
X                    errorflag = TRUE;
X                    }
X                }
X            }
X            
X
X        if (firstchar == SOH || firstchar == STX)  /* start reading packet */
X            {
X            bufsize = (firstchar == SOH) ? 128 : 1024;
X
X            if (recvsectcnt == 0)           /* 1st data packet, initialize */
X                {
X                if (bufsize == 1024)
X                    logit("1K packet mode chosen\n");
X                start = time((time_t *) 0);
X                errors = 0;
X                }
X
X	    sectcurr = readbyte(3);
X	    sectcomp = readbyte(3);
X		if ((sectcurr + sectcomp) == 0xff)  /* is packet number checksum correct? */
X		    {  
X			if (sectcurr == ((sectnum+1) & 0xff))   /* is packet number correct? */
X			    {  
X			    if (DEBUG)
X			        fprintf(LOGFP,"DEBUG: packet %d started\n", sectnum);
X
X            /* Read, process and calculate checksum for a buffer of data */
X
X			    if (readbuf(bufsize, 3, tmode, &checksum, &bufctr) != TIMEOUT) 
X                                {
X
X		    /* verify checksum or CRC */
X
X				if (CRCMODE) 
X                                    {
X				    checksum &= 0xffff;
X				    inchecksum = readbyte(3);  /* get 16-bit CRC */
X				    inchecksum = (inchecksum<<8) | readbyte(3);
X				    }
X                        
X				else
X				    inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X				if (inchecksum == checksum) /* good checksum, hence good packet */
X				    {  
X				    xmdebug("checksum ok");
X				    errors = 0;
X				    recvsectcnt += (bufsize == 128) ? 1 : 8;
X				    sectnum = sectcurr; 
X
X				    if (!openflag)      /* open output file if necessary */
X					{
X					openflag = TRUE;
X					if ((fd = creat(name, CREATMODE)) < 0)
X					    {
X					    sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X					    error("Can't create file for receive", TRUE);
X					    }
X					logitarg("File Name: %s\n", name);
X					}
X
X				    if (write(fd, (char *) buff, bufctr) < 0)
X					error("File Write Error", TRUE);
X				    else
X					sendbyte(ACK);      /* ACK the received packet */
X				    }
X
X            /* Start handling various errors and special conditions */
X
X				else        /* bad checksum */
X				    {  
X				    logitarg("Checksum Error on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
X				    errorflag = TRUE;
X				    }
X                                }
X
X			    else    /* read timeout */
X				{
X				logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
X				errorflag = TRUE;
X				}
X			    }
X
X                        else        /* sector number is wrong OR Ymodem filename */
X                            { 
X			    if (sectcurr == 0 && recvsectcnt == 0)  /* Ymodem file-name packet */
X				{
X				logit("YMODEM Batch Protocol\n");
X
X				/* Read and process a file-name packet */
X
X				if (readbuf(bufsize, 3, FALSE, &checksum, &bufctr) != TIMEOUT) 
X                                    {
X
X				    /* verify checksum or CRC */
X
X				    if (CRCMODE) 
X                                        {
X					checksum &= 0xffff;
X					inchecksum = readbyte(3);  /* get 16-bit CRC */
X					inchecksum = (inchecksum<<8) | readbyte(3);
X				        }
X                        
X				    else
X					inchecksum = readbyte(3);  /* get simple 8-bit checksum */
X
X				    if (inchecksum == checksum) /* good checksum, hence good filename */
X					{
X					xmdebug("checksum ok");
X					strcpy(name, (char *)buff);
X                                        expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
X					sendbyte(ACK);      /* ACK the packet */
X					BATCH = TRUE;
X					if (strlen(name) == 0)  /* check for no more files */
X					    {
X					    logit("YMODEM Batch Receive Complete\n");
X					    return (FALSE);
X					    }
X                                        unixify(name);       /* make filename canonical */
X					logitarg("YMODEM file name: %s\n", name);
X					logitarg("YMODEM estimated file length %d sectors\n", expsect);
X					logitarg("YMODEM header info: %s\n", (char *)buff + strlen(name) + 1);
X					}
X
X				    else                /* bad filename checksum */
X					{
X					logit("checksum error on filename sector\n");
X					errorflag = TRUE;
X					}
X				    }
X				else
X				    {
X				    logit("Timeout while reading filename packet\n");
X				    errorflag = TRUE;
X                                    }
X				}
X
X			    else if (sectcurr == sectnum)   /* duplicate sector? */
X				{  
X				logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
X				while(readbyte(3) != TIMEOUT)
X				    ;
X				sendbyte(ACK);
X				}
X			    else                /* no, real phase error */
X				{
X				logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
X				errorflag = TRUE;
X				fatalerror = TRUE;
X				sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X				}
X			    }
X		    }
X
X		else        /* bad packet number checksum */
X		    {  
X		    logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
X		    errorflag = TRUE;
X		    }
X
X	    }           /* END reading packet loop */
X    
X	if ((errorflag && !fatalerror) || recvsectcnt == 0) /* check on errors or batch transfers */
X	    {  
X	    if (errorflag)
X	        errors++;
X	    if (recvsectcnt != 0)
X		while (readbyte(3) != TIMEOUT)  /* wait for line to settle if not beginning */
X		    ;
X
X	    if (CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
X		{
X		CRCMODE = FALSE;
X		logit("Sender not accepting CRC request, changing to checksum\n");
X		sendbyte(NAK);
X		}
X	    else if (!CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
X		{
X		CRCMODE = TRUE;
X		logit("Sender not accepting checksum request, changing to CRC\n");
X		sendbyte(CRCCHR);
X		}
X	    else if (CRCMODE && recvsectcnt == 0)
X		sendbyte(CRCCHR);
X	    else
X		sendbyte(NAK);
X	    }
X	}
X        while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror);   /* end of MAIN Do-While */
X
X	if ((firstchar == EOT) && (errors < ERRORMAX))  /* normal exit? */
X	    {
X	    close(fd);
X	    sendbyte(ACK);
X	    logit("Receive Complete\n");
X	    prtime (recvsectcnt, time((time_t *) 0) - start);
X        
X	    if (BATCH)          /* send appropriate return code */
X		return(TRUE);
X	    else
X		return(FALSE);
X	    }
X	else                /* no, error exit */
X	    { 
X	    if (recvsectcnt != 0)
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		error("ABORTED -- Too Many Errors", TRUE);
X		return (FALSE);
X	    }
X    }
!Funky!Stuff!
echo x - send.c
sed -e 's/^X//' > send.c << '!Funky!Stuff!'
X/**  send a file  **/
X
X/*
X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
X *
X * If "name" is NULL; close out the BATCH send.
X */
X
X#include "xmodem.h"
X
Xsfile(name)
Xchar *name;
X	{
X
X	char *sectdisp();
X	time_t time();
X	char *strcpy();
X	char *unix_cpm();
X
X	extern unsigned short crctab[1<<B];	/* CRC-16 constant values, see getput.c */
X
X	register int bufctr, 		/* array index for data buffer */
X	sectnum;			/* packet number for packet header */
X
X	register unsigned short checksum; 	/* checksum/crc */
X
X	char blockbuf[BBUFSIZ+6];	/* holds packet as it is constructed */
X
X	struct stat filestatbuf;	/* file status info */
X
X	int fd, 		/* file descriptor for file being transmitted */
X	errors,			/* cumulative count of errors */
X	attempts,		/* number of attempts made to transmit a packet */
X	nlflag, 		/* flag that we have to send a LF in next packet */
X	sendfin, 		/* flag that we are sending the last packet */
X	closeout,		/* flag that we are closing out batch send */
X	tmode,			/* TRUE for text mode; FALSE for binary mode */
X	bbufcnt,		/* array index for packet */
X	firstchar,		/* first character in protocol transaction */
X	bufsize,		/* packet size (128 or 1024) */
X	sendresp,  		/* response char to sent block received from remote*/
X	extrachar;		/* count of extra LF characters added */
X	long sentsect;		/* count of 128 byte sectors actually sent */
X	long expsect;		/* count of 128 byte sectors expected to be sent */
X	time_t start;		/* starting time of transfer */
X	char c;
X
X	nbchr = 0;  /* clear buffered read char count */
X
X	CRCMODE = FALSE;	/* Receiver determines use of crc or checksum */
X
X	closeout = FALSE;	/* Check on NULL file name */
X	if (strcmp(name,"") == 0)
X		{
X		if (BATCH)
X			closeout = TRUE;
X		else
X			{
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X			error("NULL file name in send", TRUE);
X			}
X		}
X
X	if (!closeout)		/* Are we closing down batch? */
X		{			/* no; let's send a file */
X		if ((fd = open(name, 0)) < 0)	
X			{  
X			sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X     	   		error("Can't open file for send", TRUE);
X			}
X	
X		stat(name, &filestatbuf);  /* get file status bytes */
X		expsect = (filestatbuf.st_size/128) + 1;
X	
X		if (LOGFLAG)
X			{   
X			fprintf(LOGFP, "----\nXMODEM Send Function\n");
X		    	fprintf(LOGFP, "File Name: %s\n", name);
X		  	fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
X		  	  (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
X			projtime(expsect, LOGFP);
X			}
X		}
X	else
X		{
X		logit("----\nXMODEM Send Function\n");
X		logit("Closing down Batch Transmission\n");
X		}
X
X
X	tmode = (XMITTYPE == 't') ? TRUE : FALSE;	/* set text mode */
X
X	bufsize = LONGPACK ? 1024 : 128;		/* set sector size */
X	if (LONGPACK && !closeout)
X		logit("1K packet mode chosen\n");
X
X        sendfin = nlflag = FALSE;
X  	attempts = 0;
X
X	/* wait for and read startup character */
X	do
X		{
X		while (((firstchar=readbyte(30)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
X			if (++attempts > NAKMAX)
X				error("Remote System Not Responding", TRUE);
X
X		if ((firstchar & 0x7f) == CAN)
X			if (readbyte(3) == CAN)
X				error("Send cancelled at user's request",TRUE);
X
X		if (firstchar == CRCCHR)
X			{
X			CRCMODE = TRUE;
X			if (!closeout)
X				logit("CRC mode requested\n");
X			}
X		}
X	while (firstchar != NAK && firstchar != CRCCHR);
X
X	if (closeout && MDM7BAT)	/* close out MODEM7 batch */
X		{
X		sendbyte(ACK); sendbyte (EOT);
X		readbyte(2);			/* flush junk */
X		return;
X		}
X
X	if (MDM7BAT)		/* send MODEM7 file name and resync for data packets */
X		{
X		if (send_name(unix_cpm(name)) == -1)		/* should do better job here!! */
X			error("MODEM7-batch filename transfer botch", TRUE);
X
X		firstchar = readbyte(5);
X		if (firstchar != CRCCHR  && firstchar != NAK)	/* Should do some better error handling!!! */
X			error("MODEM7 protocol botch, NAK/C expected", TRUE);
X
X		CRCMODE = FALSE;
X		if (firstchar == CRCCHR)
X			{
X			CRCMODE = TRUE;
X			logit("CRC mode requested for MODEM7 batch transfer\n");
X			}
X		}
X
X	sectnum = 1;
X
X	if (YMDMBAT)	/* Fudge for YMODEM transfer (to send name packet) */
X		{
X		sectnum = 0;
X		bufsize = 128;
X		}
X
X	attempts = errors = sentsect = extrachar = 0;
X	start = time((time_t *) 0);
X
X        do 			/* outer packet building/sending loop; loop till whole file is sent */
X		{   
X
X		if (closeout && YMDMBAT && sectnum == 1)	/* close out YMODEM */
X			return;
X
X		if (YMDMBAT && sectnum == 1)			/* get set to send YMODEM data packets */
X			{
X			bufsize = LONGPACK ? 1024 : 128;
X			do
X				{
X				while (((firstchar=readbyte(3)) != CRCCHR) && (firstchar != CAN))
X					if (++attempts > NAKMAX)
X						error("YMODEM protocol botch, C expected", TRUE);
X				if ((firstchar&0x7f) == CAN)
X					if (readbyte(3) == CAN)
X						error("Send cancelled at User's request", TRUE);
X				}
X			while (firstchar != CRCCHR);
X			attempts = 0;
X			}
X
X		if (extrachar >= 128)	/* update expected sector count */
X			{
X			extrachar = 0;
X			expsect++;
X			}
X
X		if ((bufsize == 1024) && (errors > KSWMAX))
X			{
X			logit("Reducing packet size to 128 due to excessive errors\n");
X			bufsize = 128;
X			}
X
X		if ((bufsize == 1024) && ((expsect - sentsect) < 8))
X			{
X			logit("Reducing packet size to 128 for tail end of file\n");
X			bufsize = 128;
X			}
X
X		if (sectnum > 0)	/* data packet */
X			{
X			for (bufctr=0; bufctr < bufsize;)
X	    			{
X				if (nlflag)
X	       	 			{  
X					buff[bufctr++] = LF;  /* leftover newline */
X	       	    			nlflag = FALSE;
X	        			}
X				if (getbyte(fd, &c) == EOF)
X					{ 
X					sendfin = TRUE;  /* this is the last sector */
X		   			if (!bufctr)  /* if EOF on sector boundary */
X		      				break;  /* avoid sending extra sector */
X		      			buff[bufctr++] = CTRLZ;  /* Control-Z for CP/M EOF (even do it for binary file) */
X		   			continue;
X		      			}
X	
X				if (tmode && c == LF)  /* text mode & Unix newline? */
X		    			{
X					extrachar++;
X					buff[bufctr++] = CR;  /* insert carriage return */
X			     		if (bufctr < bufsize)
X		                		buff[bufctr++] = LF;  /* insert LF */
X		 	      		else
X			        		nlflag = TRUE;  /* insert on next sector */
X		   			}	
X				else
X					buff[bufctr++] = c;  /* copy the char without change */
X		    		}
X
X	    		if (!bufctr)  /* if EOF on sector boundary */
X   	       			break;  /* avoid sending empty sector */
X			}	
X
X		else		/* YMODEM filename packet */
X			{
X			for (bufctr=0; bufctr<bufsize; bufctr++)
X				buff[bufctr]=0;
X			if (!closeout)
X				{
X				cpmify(name);
X				strcpy((char *)buff, name);
X				buff[bufsize-2]	= (expsect & 0xff);
X				buff[bufsize-1] = ((expsect >> 8) & 0xff);
X				}
X			}
X
X		bbufcnt = 0;		/* start building block to be sent */
X		blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
X		blockbuf[bbufcnt++] = sectnum;	    /* current sector # */
X		blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
X
X               	checksum = 0;  /* initialize checksum */
X               	for (bufctr=0; bufctr < bufsize; bufctr++)
X       			{
X			blockbuf[bbufcnt++] = buff[bufctr];
X
X			if (CRCMODE)
X				checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
X
X			else
X               			checksum = ((checksum+buff[bufctr]) & 0xff);
X         		}
X
X		if (CRCMODE)		/* put in CRC */
X			{
X			checksum &= 0xffff;
X			blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
X			blockbuf[bbufcnt++] = (checksum & 0xff);
X			}
X		else			/* put in checksum */
X			blockbuf[bbufcnt++] = checksum;
X
X            	attempts = 0;
X	
X            	do				/* inner packet loop */
X            		{
X
X			writebuf(blockbuf, bbufcnt);	/* write the block */
X
X			if (DEBUG)
X				fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", 
X				bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
X
X                	attempts++;
X			sendresp = readbyte(10);  /* get response from remote */
X
X			if (sendresp != ACK)
X		   		{
X				errors++;
X
X				if ((sendresp & 0x7f) == CAN)
X					if ((readbyte(3) & 0x7f) == CAN)
X						error("Send cancelled at user's request\n",TRUE);
X
X				if (sendresp == TIMEOUT)
X					{
X		   			logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
X					}
X				else
X					{
X		   			logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
X					}
X		   		}
X            		}
X			while((sendresp != ACK) && (attempts < RETRYMAX) && (errors < ERRORMAX)); /* close of inner loop */
X
X       		sectnum++;  /* increment to next sector number */
X		sentsect += (bufsize == 128) ? 1 : 8;
X    		}
X		while (!sendfin && (attempts < RETRYMAX) && ( errors < ERRORMAX));  /* end of outer loop */
X
X    	if (attempts >= RETRYMAX)
X		{
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		error("Remote System Not Responding", TRUE);
X		}
X
X	if (attempts > ERRORMAX)
X		{
X		sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
X		error ("Too many errors in transmission", TRUE);
X		}
X
X    	attempts = 0;
X    	sendbyte(EOT);  /* send 1st EOT to close down transfer */
X	
X    	while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) 	/* wait for ACK of EOT */
X		{
X		logit("EOT not ACKed\n");
X	   	sendbyte(EOT);
X		}
X
X    	if (attempts >= RETRYMAX)
X	   	error("Remote System Not Responding on Completion", TRUE);
X
X    	close(fd);
X
X    	logit("Send Complete\n");
X	prtime(sentsect, time((time_t *) 0) - start);
X	}
!Funky!Stuff!
exit



More information about the Mod.sources mailing list