andrews@hpcupt1.HP.COM (Edward E. Andrews) (03/25/88)
/*
* XMODEM -- Implements the Christensen XMODEM protocol,
* for packetized file up/downloading.
*
* I have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty
* structures, gettimeofday system call, etc.) in the source file
* getput.c; but I make no guarantees. Also, I have made no attempt to
* keep variable names under 7 characters (although a cursory check
* shows that all variables are unique within 7 first characters).
* See the README file for some notes on SYS V adaptations.
* The program has been successfully run on VAXes (4.3BSD) and SUN-3s
* (2.x/3.x) against MEX-PC and ZCOMM/DSZ.
*
* -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
*
* XMODEM Version 1.0 - by Brian Kantor, UCSD (3/84)
*
* Version 2.0 (CRC-16 and Modem7 batch file transfer) -- Steve Grandi, NOAO (5/85)
*
* Version 2.1 (1K packets) -- Steve Grandi, NOAO (7/85)
*
* Version 2.2 (general clean-ups and multi-character read speed-ups) -- Steve Grandi, NOAO (9/85)
*
* Version 2.3 (napping while reading packet; split into several source files) -- Steve Grandi, NOAO (1/86)
*
* Version 3.0 (Ymodem batch receive; associated changes) -- Steve Grandi, NOAO (2/86)
*
* Version 3.1 (Ymodem batch send; associated changes) -- Steve Grandi, NOAO (8/86)
*
* Version 3.2 (general cleanups) -- Steve Grandi, NOAO (9/86)
*
* Released to the world (1/87)
*
* Version 3.3 (see update.doc) -- Steve Grandi, NOAO (5/87)
*
* Version 3.4 (see update.doc) -- Steve Grandi, NOAO (10/87)
*
* Released to the world (1/88)
*
* Please send bug fixes, additions and comments to:
* {ihnp4,hao}!noao!grandi grandi@noao.arizona.edu
*/
#include "xmodem.h"
main(argc, argv)
int argc;
char **argv;
{
char *getenv();
FILE *fopen();
char *unix_cpm();
char *strcpy();
char *strcat();
char *fname = filename; /* convenient place to stash file names */
char *logfile = "xmodem.log"; /* Name of LOG File */
char *stamptime(); /* for timestamp */
char *defname = "xmodem.in"; /* default file name if none given */
struct stat filestatbuf; /* file status info */
int index;
char flag;
long expsect;
/* initialize option flags */
XMITTYPE = 't'; /* assume text transfer */
DEBUG = FALSE; /* keep debugging info in log */
RECVFLAG = FALSE; /* not receive */
SENDFLAG = FALSE; /* not send either */
BATCH = FALSE; /* nor batch */
CRCMODE = FALSE; /* use checksums for now */
DELFLAG = FALSE; /* don't delete old log file */
LOGFLAG = TRUE; /* keep log */
LONGPACK = FALSE; /* do not use long packets on transmit */
MDM7BAT = FALSE; /* no MODEM7 batch mode */
YMDMBAT = FALSE; /* no YMODEM batch mode */
TOOBUSY = FALSE; /* not too busy for sleeping in packet read */
printf("XMODEM Version %d.%d", VERSION/10, VERSION%10);
printf(" -- UNIX-Microcomputer Remote File Transfer Facility\n");
if (argc == 1)
{
help();
exit(-1);
}
index = 0; /* set index for flag loop */
while ((flag = argv[1][index++]) != '\0')
switch (flag) {
case '-' : break;
case 'X' :
case 'x' : DEBUG = TRUE; /* turn on debugging log */
break;
case 'C' :
case 'c' : CRCMODE = TRUE; /* enable CRC on receive */
break;
case 'D' :
case 'd' : DELFLAG = TRUE; /* delete log file */
break;
case 'L' :
case 'l' : LOGFLAG = FALSE; /* turn off log */
break;
case 'm' :
case 'M' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */
BATCH = TRUE;
break;
case 'y' :
case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */
BATCH = TRUE;
break;
case 'k' :
case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */
break;
case 't' :
case 'T' : TOOBUSY = TRUE; /* turn off sleeping */
break;
case 'R' :
case 'r' : RECVFLAG = TRUE; /* receive file */
XMITTYPE = gettype(argv[1][index++]); /* get t/b */
break;
case 'S' :
case 's' : SENDFLAG = TRUE; /* send file */
XMITTYPE = gettype(argv[1][index++]);
break;
default : printf ("Invalid Flag %c ignored\n", flag);
break;
}
if (DEBUG)
LOGFLAG = TRUE;
if (LOGFLAG)
{
if ((fname = getenv("HOME")) == 0) /* Get HOME variable */
error("Fatal - Can't get Environment!", FALSE);
fname = strcat(fname, "/");
fname = strcat(fname, logfile);
if (!DELFLAG)
LOGFP = fopen(fname, "a"); /* append to LOG file */
else
LOGFP = fopen(fname, "w"); /* new LOG file */
if (!LOGFP)
error("Fatal - Can't Open Log File", FALSE);
fprintf(LOGFP,"\n++++++++ %s", stamptime());
fprintf(LOGFP,"XMODEM Version %d.%d\n", VERSION/10, VERSION%10);
fprintf(LOGFP,"Command line: %s %s", argv[0], argv[1]);
for (index=2; index<argc; ++index)
fprintf(LOGFP, " %s", argv[index]);
fprintf(LOGFP, "\n");
}
getspeed(); /* get tty-speed for time estimates */
if (RECVFLAG && SENDFLAG)
error("Fatal - Both Send and Receive Functions Specified", FALSE);
if (MDM7BAT && YMDMBAT)
error("Fatal - Both YMODEM and MODEM7 Batch Protocols Specified", FALSE);
if (!RECVFLAG && !SENDFLAG)
error("Fatal - Either Send or Receive Function must be chosen!",FALSE);
if (SENDFLAG && argc==2)
error("Fatal - No file specified to send",FALSE);
if (RECVFLAG && argc==2)
{
/* assume we really want CRC-16 in batch, unless we specify MODEM7 mode */
CRCMODE = MDM7BAT ? FALSE : TRUE;
printf("Ready for BATCH RECEIVE");
printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
printf("Send several Control-X characters to cancel\n");
logit("Batch Receive Started");
logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
strcpy(fname, defname);
}
if (RECVFLAG && argc>2)
{
if(open(argv[2], 0) != -1) /* check for overwriting */
{
logit("Warning -- Target File Exists and is Being Overwritten\n");
printf("Warning -- Target File Exists and is Being Overwritten\n");
}
printf("Ready to RECEIVE File %s", argv[2]);
printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
printf("Send several Control-X characters to cancel\n");
logitarg("Receiving in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
strcpy(fname,argv[2]);
}
if (RECVFLAG)
{
setmodes(); /* set tty modes for transfer */
while(rfile(fname) != FALSE); /* receive files */
restoremodes(FALSE); /* restore normal tty modes */
sleep(2); /* give other side time to return to terminal mode */
exit(0);
}
if (SENDFLAG && BATCH)
{
if (YMDMBAT)
{
printf("Ready to YMODEM BATCH SEND");
printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
logit("YMODEM Batch Send Started");
logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
}
else if (MDM7BAT)
{
printf("Ready to MODEM7 BATCH SEND");
printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
logit("MODEM7 Batch Send Started");
logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
}
printf("Send several Control-X characters to cancel\n");
setmodes();
for (index=2; index<argc; index++) {
if (stat(argv[index], &filestatbuf) < 0) {
logitarg("\nFile %s not found\n", argv[index]);
continue;
}
sfile(argv[index]);
}
sfile("");
restoremodes(FALSE);
logit("Batch Send Complete\n");
sleep(2);
exit (0);
}
if (SENDFLAG && !BATCH)
{
if (stat(argv[2], &filestatbuf) < 0)
error("Can't find requested file", FALSE);
expsect = (filestatbuf.st_size/128)+1;
printf("File %s Ready to SEND", argv[2]);
printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
printf("Estimated File Size %ldK, %ld Sectors, %ld Bytes\n",
(filestatbuf.st_size/1024)+1, expsect,
filestatbuf.st_size);
projtime(expsect, stdout);
printf("Send several Control-X characters to cancel\n");
logitarg("Sending in %s mode\n", (XMITTYPE == 't') ? "text" : "binary");
setmodes();
sfile(argv[2]);
restoremodes(FALSE);
sleep(2);
exit(0);
}
}andrews@hpcupt1.HP.COM (Edward E. Andrews) (03/25/88)
#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sgtty.h>
#include <signal.h>
/* define macros to print messages in log file */
#define logit(string) if(LOGFLAG)fprintf(LOGFP,string)
#define logitarg(string,argument) if(LOGFLAG)fprintf(LOGFP,string,argument)
#define VERSION 34 /* Version Number */
#define FALSE 0
#define TRUE 1
/* ASCII Constants */
#define SOH 001
#define STX 002
#define ETX 003
#define EOT 004
#define ENQ 005
#define ACK 006
#define LF 012 /* Unix LF/NL */
#define CR 015
#define NAK 025
#define SYN 026
#define CAN 030
#define ESC 033
/* XMODEM Constants */
#define TIMEOUT -1
#define ERRORMAX 10 /* maximum errors tolerated while transferring a packet */
#define WAITFIRST 1 /* seconds between startup characters in read */
#define STERRORMAX 60 /* maximum "errors" tolerated in read startup */
#define CRCSWMAX 30 /* maximum time to try CRC mode before switching */
#define NAKMAX 120 /* maximum times to wait for initial NAK when sending */
#define RETRYMAX 5 /* maximum retries to be made certain handshaking routines */
#define KSWMAX 5 /* maximum errors before switching to 128 byte packets */
#define EOTMAX 10 /* maximum times sender will send an EOT to end transfer */
#define SLEEPNUM 100 /* target number of characters to collect during sleepy time */
#define BBUFSIZ 1024 /* buffer size */
#define NAMSIZ 11 /* length of a CP/M file name string */
#define CTRLZ 032 /* CP/M EOF for text (usually!) */
#define CRCCHR 'C' /* CRC request character */
#define KCHR 'K' /* 1K block request character */
#define BAD_NAME 'u' /* Bad filename indicator */
#define CREATMODE 0644 /* mode for created files */
/* GLOBAL VARIABLES */
int ttyspeed; /* tty speed (bits per second) */
unsigned char buff[BBUFSIZ]; /* buffer for data */
int nbchr; /* number of chars read so far for buffered read */
long filelength; /* length specified in YMODEM header */
long fileread; /* characters actually read so far in file */
char filename[256]; /* place to construct filenames */
FILE *LOGFP; /* descriptor for LOG file */
/* option flags and state variables */
char XMITTYPE; /* text or binary? */
int DEBUG; /* keep debugging info in log? */
int RECVFLAG; /* receive? */
int SENDFLAG; /* send? */
int BATCH; /* batch? (Now used as a state variable) */
int CRCMODE; /* CRC or checksums? */
int DELFLAG; /* don't delete old log file? */
int LOGFLAG; /* keep log? */
int LONGPACK; /* do not use long packets on transmit? */
int MDM7BAT; /* MODEM7 batch protocol */
int YMDMBAT; /* YMODEM batch protocol */
int TOOBUSY; /* turn off sleeping in packet read routine */
int CHECKLENGTH; /* Are we truncating a file to a YMODEM length? */
/* CRC-16 constants. From Usenet contribution by Mark G. Mendel,
Network Systems Corp. (ihnp4!umn-cs!hyper!mark)
*/
/* the CRC polynomial. */
#define P 0x1021
/* number of bits in CRC */
#define W 16
/* the number of bits per char */
#define B 8