home *** CD-ROM | disk | FTP | other *** search
- Subject: v13i096: Full featured xmodem program, v3.4, Patch1
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Steve Grandi <grandi@noao.arizona.edu>
- Posting-number: Volume 13, Issue 96
- Archive-name: xmodem3.4/patch1
-
-
- Here is a message I just posted to comp.sources.bugs....
-
- 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@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@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
-
-