perl@rdin2.UUCP (Robert Perlberg) (05/16/84)
<>
Thanks to the people who sent me information on tranfering
files between UNIX and PC-DOS.
The package most recommended was KERMIT. Here are some of
the comments I received on it:
It is a public-domain terminal emulator and file
transfer package that runs on *MANY* different mainframes, minis, and micros,
with many maintainers and central coordination. Cost ~$100.
There is a C version for Unix, and an assembler version for the PC.
The UNIX version is still a little buggy, but they are
working on fixing it. Mail to CC.FDC@Columbia-20.ARPA for more information.
His name is Frank DeCruise (sp?). Contact
Daphne Tzoar
Columbia University Computer Center
612 W. 115th St.
New York City, NY 10025
for more information, or you can get the files via anonymous ftp via the
arpanet. Connect to COLUMBIA-20, and look at directory <KERMIT>, or they
can mail you a magtape with all the files in the <KERMIT> directory.
There is a special interest group on KERMIT available on the ARPA
net as:
INFO-KERMIT@COLUMBIA-20
of course requests would be routed to
INFO-KERMIT-REQUEST@COLUMBIA-20
Here are the rest of the responses:
---
there are versions of the CP/M modem program for both MS-DOS and Unix
(also tops-20, Xerox lisp machines and others). See SIMTEL-20
---
General Micro Systems has a "PC-100" vt100 emulator which is available
under PC-DOS or QNX (which I use). It uploads and downloads with
4.2bsd quite successfully.
GMS
7525 Mitchell Rd.
Suite 101
Eden Prairie, MN 55344
---
IF you have the PC/XT, you should look into Venix/86 offered by
Unisource Software Corp. (617-491-1264) for $800. Venix is an
implementation of UNIX System III for PCs (Venix/86 is specifically
for the IBM), and includes cu and uucp. If you don't have a hard
disk, I think Unisource offers a package (10 Meg hard disk with
Venix loaded) - can't recall their price.
---
There is a product called PC Works which is supposed to set up a pretty nice
network between a UNIX system and one or more PC's. One of our customers
(Molecular Compuer) ported this to one of our systems in fairly short order ;
it may well already be available for the Masscomp. Our marketing department
picked up on this in a hurry and want to sell it (I have to approve it
first, and I haven't seen a copy yet, so I can't tell you anything more
useful). As our marketing people want to price it, it runs $495 for the
basic product, plus $195 for each additional PC (beyond the first one) that
you want to hook up. I don't know if this is in line with what you want,
but if it sounds interesting I will dredge up the name/address of the company
that produces it, and mail it to you, and you can contact them yourself.
Mats Wichmann
Dual Systems Corp.
...{ucbvax,amd70,ihnp4,cbosgd,decwrl,fortune}!dual!mats
---
I have found the terminal emulator written by Jim Holtman and his son
to be quite good - also its free, and the source comes with it. What more
could a person ask?
It makes the IBM PC emulate either an "HP-like" terminal or an adm3a. It
does require the rs232int part of the IBM Asynchronous Comm Support. Its
written in IBM Pascal (I recompiled the whole thing, and it still worked;
something I can't say for all the software I've tried that on). It starts
up *much* faster than the IBM emulator; the adm3a is a good emulation
(works with vi and some other software that I've tried. A ventel
autodialing modem is supported.
For file transfer, you can do it the hard way (invoke ed or something, then
dump the IBM file to the line, then finish up), an automatic up/down link
(just for IBM<->UNIX; it does the work), and XMODEM protocols (the UNIX
end source is provided too).
All in all, an excellent working package. Jim's addresses are:
Jim Holtman 201/361-3395
35 Dogwood Trail harpo!whuxlb!jph
Randolph, NJ 07869
Thanks, Jim!
--
Lyle McElhaney
(hao,brl-bmd,nbires,csu-cs,scgvaxd)!denelcor!lmc
---
I posted the source of `xsend' and `xrecv' which allow (multiple)
file transfer between PC and UN*X based on XMODEM protocol.
What you need to run on your PC/XT is either a PERFECT LINK,
PC-TALK III (from Freeware) or MODEM7xx program (which is being
circulated around PC community for free also). If you have any
further questions on that, mail me.
kha sin
---
The PC/InterComm terminal emulator from Mark of the Unicorn can handle
XMODEM on the PC side. The UMODEM public domain XMODEM program for UNIX
is available on BBSs, etc. Also, you may use the XMODEM spec published
in net.sources a week ago to write your own program.
Gary Samad
---
Hi,
This is in response to your message on Usenet, regarding your
search for a convenient file transfer system between a PC and a UNIX
system. I think my company may have a pretty good answer for you.
LINK/pc is a vt100/vt52/ibm 3101 emulator that has most of
the standard stuff you would expect from a terminal emulation/file
transfer package (including command scripts for auto-login, DC-Hayes
modem manipulation, etc.). In addition to being able to do file transfer
in the conventional inconvenient way, however, LINK/pc also allows
file transfers to be remotely invoked - the UNIX system can
tell the PC that a file is about to be transferred up to it, or that it
should transfer a file down to the UNIX system. This allows us to put
control of the operation into one set of hands. In our case, however,
we chose to put the control into the more powerful hands - the UNIX system.
Using this facility, we have put together a couple of simple tools -
utopccp and pctoucp that have a "cp" like syntax but are used for copying
files between a PC and a UNIX system. For example,
utopccp *.c *.h a:
will transfer all files with .c and .h suffixes to drive a: on the pc.
Similarly,
pctoucp c:xyz.dat a:abc.dat .
will transfer the indicated files to the current directory. We have the
xmodem protocol implemented if you wish to do the transfer using
an error correcting protocol. Naturally, you can include these commands
in any aliases, or shell scripts you might have - the only caveat being
that the commands do assume that they have exclusive use of the tty line
for the duration of their execution.
The source for these commands and 5 (or 6?) simpler example programs
is included when you get a LINK/pc
But wait! There's more! LINK/pc also allows you to remotely
execute PC-DOS commands. In a similar fashion to the file transfer, the
UNIX system can tell the PC (running DOS V2.0 with >192K of memory)
to execute a program. Upon termination of the program you are returned to
LINK/pc. We also provide a nice UNIX cover utility for this capablity,
that you can include in shell scripts, aliases, etc.. I have a couple
of aliases, "dir" and "type" that allow me to transparently get directory
listings and view the contents of files without ever leaving LINK/pc or
UNIX. This facility is very good for programs like spreadsheets,
that are better suited to PCs than UNIX systems.
If you are interested, I would be happy to send you a brochure.
If you are very interested, the program costs $195.00 for version 2.0
(xmodem and remote program invokation). There are steep discounts for volume
purchases, etc., etc..
I will be interested in seeing the results of your survey.
Yours,
Douglas Orr
P.S.
Our addresses are:
sb1!mb2c!uofm-cv!cosivax!dbo
COSI
313 N. First St.
Ann Arbor, Mi. 48103
(313) 665-8778
---
I believe umodem, written in C to perform with the PD modem protocols,
may be close to what you're looking for. Try the simtel archives: that's
where I got my copy.
-- sam hahn [samuel@score]
---
We have a product you might be interested in. If you send me you phone
number I will sic a salesman on you.
Cheers,
Topher Eliot
Cyb Systems, Austin, TX
{seismo, allegra, ihnp4}!ut-sally!cyb-eng!topher
---
Before I include the final response (a source), here is a
list of the people I got responses from:
acf4!mta7438 Mark Anders
kpno!brown Mike Brown
utah-cs!brownc Eric C. Brown
sun!djc dave cardinal
sdcrdcf!darrelj
cwruecmp!diamant John Diamant
cyb-eng!topher Topher Eliot
SAMUEL@SU-SCORE.ARPA sam hahn
LARSON@USC-ECLB.ARPA Bob Larson
mike@LOGICON.ARPA Mike Parker
alberta!jeff C. J. Sampson
hou2b!sims Jim Simester
auvax!khasin kha sin
dual!mats Mats Wichmann
Finally, thanks to Jim Holtman (whuxle!jph) for the offer he
posted. Thanks also to the other people who posted
responses whose names I did not save.
Here, now, is the source I received.
Robert,
I have used Crosstalk XVI for about six months now and have had
great results. The latest version that I know of, ver 3.4 has the
XMODEM protocol. I have, and am enclosing, a version of XMODEM to run
under BSD 4.2 Unix that was posted to the net a while back. I had no
trouble either downloading or uploading file between machines, and have
transfered dbaseII files between a CPM machine and MSDOS by using the
VAX as a temporary storage area. Though the XMODEM protocol is written
for BSD 4.2, and will not run directly on you system (at least that's
what I was told) it shouldn't be hard to modify it to run on yours.
Hopefully you'll be able to find an XMODEM package already written for
Sys III, and won't have to bother with this, but if not, you won't be
stuck. I should note that Crosstalk can emulate a vt100, and a few others,
so you can use vi (or play rogue), and that I had execellent results
transfering files straight ascii, but it is of course much better to use
some form of error checking. Good luck.
Mark Anders
cmcl2!acf4!mta7438
/***********************************************************************/
/*
* XMODEM Version 1.0 - by Brian Kantor, UCSD
*
* XMODEM -- Implements the "CP/M User's Group XMODEM" protocol,
* for packetized file up/downloading.
*
* This version is designed for 4.2BSD ONLY! It won't work
* ANYWHERE else - uses the 'select' system call to replace
* the old alarm handlers.
*
* -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
*
*/
#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sgtty.h>
#include <signal.h>
/* log default define */
#ifndef LOGDEFAULT
#define LOGDEFAULT 1
#endif
/* Delete logfile define. Useful on small systems with limited
* filesystem space and careless users.
*/
#ifndef DELDEFAULT
#define DELDEFAULT 1
#endif
#define VERSION 10 /* 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
#define CTRLZ 032 /* CP/M EOF for text (usually!) */
/* XMODEM Constants */
#define TIMEOUT -1
#define ERRORMAX 10 /* maximum errors tolerated */
#define RETRYMAX 10 /* maximum retries to be made */
#define BBUFSIZ 128 /* buffer size -- do not change! */
/* Mode for Created Files */
#define CREATMODE 0644 /* mode for created files */
struct sgttyb ttys, ttysnew, ttystemp; /* for stty terminal mode calls */
struct stat statbuf; /* for terminal message on/off control */
char *strcat();
FILE *LOGFP, *fopen();
char buff[BBUFSIZ];
int nbchr; /* number of chars read so far for buffered read */
int wason;
int pagelen;
char *ttyname(); /* forward declaration for C */
char *tty;
char XMITTYPE;
int CRCMODE, RECVFLAG, SENDFLAG, PMSG, DELFLAG, LOGFLAG, MUNGMODE;
int FILTER, DEBUG;
int STATDISP;
char filename[256];
main(argc, argv)
int argc;
char **argv;
{
char *getenv();
char *fname = filename;
char *logfile;
int index;
char flag;
logfile = "xmodem.log"; /* Name of LOG File */
printf("\nXMODEM Version %d.%d", VERSION/10, VERSION%10);
printf(" -- UNIX-CP/M Remote File Transfer Facility\n");
if (argc < 3)
{
help(FALSE);
exit(-1);
}
index = 0; /* set index for loop */
PMSG = FALSE; /* turn off flags */
DEBUG = FALSE;
RECVFLAG = FALSE; /* not receive */
SENDFLAG = FALSE; /* not send either */
FILTER = FALSE; /* assume literal mode */
CRCMODE = FALSE; /* use checksums for now */
XMITTYPE = 't'; /* assume text */
DELFLAG = DELDEFAULT;
LOGFLAG = LOGDEFAULT;
if (LOGFLAG)
LOGFLAG = TRUE;
else
LOGFLAG = FALSE;
MUNGMODE = FALSE; /* protect files from overwriting */
while ((flag = argv[1][index++]) != '\0')
switch (flag) {
case '-' : break;
case 'x' : DEBUG = TRUE;
break;
/* no crc mode yet
case 'c' : CRCMODE = TRUE;
xmdebug("CRC mode selected");
break;
*/
case 'd' : DELFLAG = !DELDEFAULT; /* delete log file ? */
xmdebug("delete log toggled");
break;
case 'l' : LOGFLAG = !LOGDEFAULT; /* turn off log ? */
xmdebug("write log toggled");
break;
case 'm' : MUNGMODE = TRUE; /* allow overwriting of files */
xmdebug("munge mode selected");
break;
case 'r' : RECVFLAG = TRUE; /* receive file */
XMITTYPE = gettype(argv[1][index++]); /* get t/b */
xmdebug("receive mode selected");
break;
case 's' : SENDFLAG = TRUE; /* send file */
XMITTYPE = gettype(argv[1][index++]);
xmdebug("send mode selected");
break;
case 'f' : FILTER = TRUE;
xmdebug("filter selected");
break;
default : error("Invalid Flag", FALSE);
}
if (LOGFLAG)
{
if ((fname = getenv("HOME")) == 0) /* Get HOME variable */
error("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("Can't Open Log File", FALSE);
fprintf(LOGFP,"\n\n++++++++\n");
fprintf(LOGFP,"\nXMODEM Version %d.%d\n", VERSION/10, VERSION%10);
printf("\nXMODEM: LOG File '%s' is Open\n", fname);
}
if (RECVFLAG && SENDFLAG)
error("Both Send and Receive Functions Specified", FALSE);
if (!RECVFLAG && !SENDFLAG)
error("Either Send or Receive Function must be chosen!",FALSE);
if (FILTER && (!RECVFLAG || XMITTYPE != 't'))
error("Filter is only valid in text receive mode!",FALSE);
if (RECVFLAG)
{
if(open(argv[2], 0) != -1) /* possible abort if file exists */
{
printf("\nXMODEM: Warning -- Target File Exists\n");
if( MUNGMODE == FALSE )
error("Fatal - Can't overwrite file\n",FALSE);
printf("XMODEM: Overwriting Target File\n");
}
rfile(argv[2]); /* receive file */
}
if (SENDFLAG)
sfile(argv[2]); /* send file */
if (LOGFLAG) fclose(LOGFP);
xmdebug("done");
exit(0);
}
/* Print Help Message */
help()
{
xmdebug("help:");
printf("\nUsage: \n\txmodem ");
printf("-[rb!rt!sb!st][options] filename\n");
printf("\nMajor Commands --");
printf("\n\trb <-- Receive Binary");
printf("\n\trt <-- Receive Text");
printf("\n\tsb <-- Send Binary");
printf("\n\tst <-- Send Text");
printf("\nOptions --");
#if DELDEFAULT == 1
printf("\n\td <-- Do not delete umodem.log file before starting");
#else
printf("\n\td <-- Delete umodem.log file before starting");
#endif
#if LOGDEFAULT == 1
printf("\n\tl <-- (ell) Turn OFF LOG File Entries");
#else
printf("\n\tl <-- (ell) Turn ON LOG File Entries");
#endif
/* no crc mode yet
printf("\n\tc <-- Select CRC mode on receive");
*/
printf("\n\tf <-- Filter 8-bit chars on receive - use with WordStar files");
printf("\n");
}
/* get type of transmission requested (text or binary) */
gettype(ichar)
char ichar;
{
xmdebug("gettype:");
if (ichar == 't') return(ichar);
if (ichar == 'b') return(ichar);
error("Invalid Send/Receive Parameter - not t or b", FALSE);
return;
}
/* set tty modes for XMODEM transfers */
setmodes()
{
xmdebug("setmodes:");
if (ioctl(0,TIOCGETP,&ttys)<0) /* get tty params [V7] */
error("Can't get TTY Parameters", TRUE);
tty = ttyname(0); /* identify current tty */
/* transfer current modes to new structure */
ttysnew.sg_ispeed = ttys.sg_ispeed; /* copy input speed */
ttysnew.sg_ospeed = ttys.sg_ospeed; /* copy output speed */
ttysnew.sg_erase = ttys.sg_erase; /* copy erase flags */
ttysnew.sg_flags = ttys.sg_flags; /* copy flags */
ttysnew.sg_kill = ttys.sg_kill; /* copy std terminal flags */
ttysnew.sg_flags |= RAW; /* set for RAW Mode */
/* This ORs in the RAW mode value, thereby
setting RAW mode and leaving the other
mode settings unchanged */
ttysnew.sg_flags &= ~ECHO; /* set for no echoing */
/* This ANDs in the complement of the ECHO
setting (for NO echo), thereby leaving all
current parameters unchanged and turning
OFF ECHO only */
ttysnew.sg_flags &= ~XTABS; /* set for no tab expansion */
ttysnew.sg_flags &= ~LCASE; /* set for no upper-to-lower case xlate */
ttysnew.sg_flags |= ANYP; /* set for ANY Parity */
ttysnew.sg_flags &= ~NL3; /* turn off ALL 3s - new line */
ttysnew.sg_flags &= ~TAB2; /* turn off tab 3s */
ttysnew.sg_flags &= ~CR3; /* turn off CR 3s */
ttysnew.sg_flags &= ~FF1; /* turn off FF 3s */
ttysnew.sg_flags &= ~BS1; /* turn off BS 3s */
ttysnew.sg_flags &= ~TANDEM; /* turn off flow control */
/* set new paramters */
if (ioctl(0,TIOCSETP,&ttysnew) < 0)
error("Can't set new TTY Parameters", TRUE);
if (stat(tty, &statbuf) < 0) /* get tty status */
error("Can't get your TTY Status", TRUE);
if (statbuf.st_mode & 022) /* Need to turn messages off */
if (chmod(tty, statbuf.st_mode & ~022) < 0)
error("Can't change TTY mode", TRUE);
else
wason = TRUE;
else
wason = FALSE;
xmdebug("tty modes set");
}
/* restore normal tty modes */
restoremodes(errcall)
int errcall;
{
xmdebug("restoremodes:");
if (wason)
if (chmod(tty, statbuf.st_mode | 022) < 0)
error("Can't change TTY mode", FALSE);
if (ioctl(0,TIOCSETP,&ttys) < 0)
{ if (!errcall)
error("RESET - Can't restore normal TTY Params", FALSE);
else
{ printf("XMODEM: ");
printf("RESET - Can't restore normal TTY Params\n");
}
}
xmdebug("tty modes reset");
return;
}
/* print error message and exit; if mode == TRUE, restore normal tty modes */
error(msg, mode)
char *msg;
int mode;
{
xmdebug("error:");
if (mode)
restoremodes(TRUE); /* put back normal tty modes */
printf("\r\nXMODEM: %s\n", msg);
if ((LOGFLAG || DEBUG) & (int)LOGFP)
{
fprintf(LOGFP, "XMODEM Fatal Error: %s\n", msg);
fclose(LOGFP);
}
exit(-1);
}
/** print status (size) of a file **/
yfile(name)
char *name;
{
xmdebug("yfile:");
printf("\nXMODEM File Status Display for %s\n", name);
if (open(name,0) < 0)
{
printf("File %s does not exist\n", name);
return;
}
prfilestat(name); /* print status */
printf("\n");
}
/*
*
* Get a byte from the specified file. Buffer the read so we don't
* have to use a system call for each character.
*
*/
getbyte(fildes, ch) /* Buffered disk read */
int fildes;
char *ch;
{
static char buf[BUFSIZ]; /* Remember buffer */
static char *bufp = buf; /* Remember where we are in buffer */
xmdebug("getbyte:");
if (nbchr == 0) /* Buffer exausted; read some more */
{
if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
error("File Read Error", TRUE);
bufp = buf; /* Set pointer to start of array */
}
if (--nbchr >= 0)
{
*ch = *bufp++;
return(0);
}
else
return(EOF);
}
/** receive a file **/
rfile(name)
char *name;
{
register int bufctr, checksum;
register int c;
char mode;
int fd, j, firstchar, sectnum, sectcurr, tmode;
int sectcomp, errors, errorflag, recfin;
int errorchar, fatalerror, startstx, inchecksum, endetx, endenq;
long recvsectcnt;
xmdebug("rfile:");
mode = XMITTYPE; /* set t/b mode */
if ((fd = creat(name, CREATMODE)) < 0)
error("Can't create file for receive", FALSE);
printf("XMODEM: Ready to RECEIVE File %s\n", name);
puts("Control-X to cancel.\n");
if (LOGFLAG)
{
fprintf(LOGFP, "\n----\nXMODEM Receive Function\n");
fprintf(LOGFP, "File Name: %s\n", name);
}
setmodes(); /* setup tty modes for xfer */
recfin = FALSE;
sectnum = errors = 0;
fatalerror = FALSE; /* NO fatal errors */
recvsectcnt = 0; /* number of received sectors */
if (mode == 't')
tmode = TRUE;
else
tmode = FALSE;
if (CRCMODE)
{
xmdebug("crc mode request sent");
sendbyte('C'); /* CRC request for first block */
}
else
{
xmdebug("NAK sent");
sendbyte(NAK); /* Start up the sender's first block */
}
do
{
errorflag = FALSE;
do
{
firstchar = readbyte(6);
}
while ((firstchar != SOH)
&& (firstchar != EOT)
&& (firstchar != TIMEOUT)
&& ((firstchar & 0x7f) != CAN));
if (firstchar == TIMEOUT)
{
xmdebug("first char was timeout");
if (LOGFLAG)
fprintf(LOGFP, "Timeout on Sector %d\n", sectnum);
errorflag = TRUE;
}
if ((firstchar & 0x7f) == CAN)
{
xmdebug("CAN received");
if (LOGFLAG)
fprintf(LOGFP, "Reception canceled at user's request.\n");
error("Reception canceled at user's request",TRUE);
}
if (firstchar == SOH)
{
xmdebug("SOH received");
sectcurr = readbyte(3);
sectcomp = readbyte(3);
if ((sectcurr + sectcomp) == 0xff)
{
if (sectcurr == ((sectnum+1) & 0xff))
{
checksum = 0;
for (j = bufctr = 0; j < BBUFSIZ; j++)
{
buff[bufctr] = c = readbyte(3);
checksum = ((checksum+c) & 0xff);
if (!tmode) /* binary mode */
{
bufctr++;
continue;
}
if (FILTER) /* bit 8 */
buff[bufctr] &= 0x7f;
if (c == CR)
continue; /* skip CR's */
if (c == CTRLZ) /* CP/M EOF char */
{
recfin = TRUE; /* flag EOF */
continue;
}
if (!recfin)
bufctr++;
}
inchecksum = readbyte(3); /* get checksum */
if (checksum == inchecksum) /* good checksum */
{
xmdebug("checksum ok");
errors = 0;
recvsectcnt++;
sectnum = sectcurr;
if (write(fd, buff, bufctr) < 0)
error("File Write Error", TRUE);
else
sendbyte(ACK);
}
else
{
xmdebug("checksum bad");
if (LOGFLAG)
fprintf(LOGFP, "Checksum Error on Sector %d\n",
sectnum);
errorflag = TRUE;
}
}
else
{
if (sectcurr == sectnum)
{
xmdebug("dup sector flushed");
while(readbyte(3) != TIMEOUT)
;
sendbyte(ACK);
}
else
{
xmdebug("sector out of seq");
if (LOGFLAG)
{
fprintf(LOGFP, "Phase Error - Received Sector is ");
fprintf(LOGFP, "%d while Expected Sector is %d\n",
sectcurr, ((sectnum+1) & 0xff));
}
errorflag = TRUE;
fatalerror = TRUE;
sendbyte(CAN);
}
}
}
else
{
if (DEBUG)
fprintf(LOGFP,"DEBUG: bad sector# sectcurr=%02xH, sectcomp=%02xH\n",sectcurr,sectcomp);
if (LOGFLAG)
fprintf(LOGFP, "Header Sector Number Error on Sector %d\n",
sectnum);
errorflag = TRUE;
}
}
if (errorflag)
{
xmdebug("flushing bad sector");
errors++;
while (readbyte(3) != TIMEOUT)
;
sendbyte(NAK);
}
}
while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror);
if ((firstchar == EOT) && (errors < ERRORMAX))
{
xmdebug("EOT received");
close(fd);
sendbyte(ACK);
restoremodes(FALSE); /* restore normal tty modes */
sleep(5); /* give other side time to return to terminal mode */
if (LOGFLAG)
{
fprintf(LOGFP, "\nReceive Complete\n");
fprintf(LOGFP,"Number of Received CP/M Records is %ld\n", recvsectcnt);
}
printf("\n");
}
else
{
sendbyte(CAN);
xmdebug("error limit exceeded");
error("\r\nABORTED -- Too Many Errors", TRUE);
}
}
/** send a file **/
sfile(name)
char *name;
{
register int bufctr, checksum, sectnum;
char blockbuf[134];
char mode;
int fd, attempts;
int nlflag, sendfin, tmode;
int bbufcnt;
int firstchar;
char c;
int sendresp; /* response char to sent block */
xmdebug("sfile:");
nbchr = 0; /* clear buffered read char count */
mode = XMITTYPE; /* set t/b mode */
if ((fd = open(name, 0)) < 0)
{
if (LOGFLAG) fprintf(LOGFP, "Can't Open File\n");
error("Can't open file for send", FALSE);
}
printf("XMODEM: File %s Ready to SEND\n", name);
prfilestat(name); /* print file size statistics */
puts("\nControl-X to cancel.\n");
if (LOGFLAG)
{
fprintf(LOGFP, "\n----\nXMODEM Send Function\n");
fprintf(LOGFP, "File Name: %s\n", name);
}
if (mode == 't')
tmode = TRUE;
else
tmode = FALSE;
sendfin = nlflag = FALSE;
attempts = 0;
setmodes(); /* setup tty modes for xfer */
while (((firstchar=readbyte(30)) != NAK)
/* no crc mode yet
&& (firstchar != 'C')
*/
&& (firstchar != CAN))
{
if (++attempts > RETRYMAX)
error("Remote System Not Responding", TRUE);
}
if ((firstchar & 0x7f) == CAN)
{
xmdebug("can received");
error("\nSend cancelled at user's request.\n",TRUE);
exit(-1);
}
sectnum = 1; /* first sector number */
attempts = 0;
do
{
for (bufctr=0; bufctr < BBUFSIZ;)
{
if (nlflag)
{
buff[bufctr++] = LF; /* leftover newline */
nlflag = FALSE;
}
if (getbyte(fd, &c) == EOF)
{
sendfin = TRUE; /* this is the last sector */
if (!bufctr) /* if EOF on sector boundary */
break; /* avoid sending extra sector */
if (tmode)
buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF */
else
bufctr++;
continue;
}
if (tmode && c == LF) /* text mode & Unix newline? */
{
buff[bufctr++] = CR; /* insert carriage return */
if (bufctr < BBUFSIZ)
buff[bufctr++] = LF; /* insert LF */
else
nlflag = TRUE; /* insert on next sector */
}
else
buff[bufctr++] = c; /* copy the char without change */
}
attempts = 0;
if (!bufctr) /* if EOF on sector boundary */
break; /* avoid sending empty sector */
do
{
bbufcnt = 0; /* start building block to be sent */
blockbuf[bbufcnt++] = SOH; /* start of packet char */
blockbuf[bbufcnt++] = sectnum; /* current sector # */
blockbuf[bbufcnt++] = -sectnum-1; /* and its complement */
checksum = 0; /* init checksum */
for (bufctr=0; bufctr < BBUFSIZ; bufctr++)
{
blockbuf[bbufcnt++] = buff[bufctr];
checksum = ((checksum+buff[bufctr]) & 0xff);
}
blockbuf[bbufcnt++] = checksum;
write(1, blockbuf, 132); /* write the block */
ioctl(1,TIOCFLUSH,0);
attempts++;
sendresp = readbyte(10); /* get response */
if ((sendresp != ACK) && LOGFLAG)
{
fprintf(LOGFP, "Non-ACK Received on Sector %d\n",sectnum);
if (sendresp == TIMEOUT)
fprintf(LOGFP, "This Non-ACK was a TIMEOUT\n");
}
}
while((sendresp != ACK) && (attempts < RETRYMAX));
sectnum++; /* increment to next sector number */
}
while (!sendfin && (attempts < RETRYMAX));
if (attempts >= RETRYMAX)
error("Remote System Not Responding", TRUE);
attempts = 0;
sendbyte(EOT); /* send 1st EOT */
while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX))
sendbyte(EOT);
if (attempts >= RETRYMAX)
error("Remote System Not Responding on Completion", TRUE);
close(fd);
restoremodes(FALSE);
sleep(15); /* give other side time to return to terminal mode */
if (LOGFLAG)
fprintf(LOGFP, "\nSend Complete\n");
printf("\n");
}
/* print file size status information */
prfilestat(name)
char *name;
{
struct stat filestatbuf; /* file status info */
xmdebug("prfilestat:");
stat(name, &filestatbuf); /* get file status bytes */
printf(" Estimated File Size %ldK, %ld Records, %ld Bytes",
(filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
filestatbuf.st_size);
if (LOGFLAG)
fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
(filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
filestatbuf.st_size);
return;
}
/* get a byte from data stream -- timeout if "seconds" elapses */
int readbyte(seconds)
int seconds;
{
int i, readfd;
char c;
struct timeval tmout;
tmout.tv_sec = seconds;
tmout.tv_usec = 0;
readfd = 1;
if ((i=select(1, &readfd, 0, 0, &tmout)) == 0)
{
xmdebug("readbyte timeout");
return(TIMEOUT);
}
if (DEBUG)
fprintf(LOGFP,"DEBUG: readbyte select returned %d\n",i);
read(0, &c, 1);
if (DEBUG)
fprintf(LOGFP,"DEBUG: readbyte %02xh\n",c);
return(c & 0xff); /* return the char */
}
/* send a byte to data stream */
sendbyte(data)
char data;
{
if (DEBUG)
fprintf(LOGFP,"DEBUG: sendbyte %02xh\n",data);
write(1, &data, 1); /* write the byte */
ioctl(1,TIOCFLUSH,0); /* flush so it really happens now! */
return;
}
/* type out debugging info */
xmdebug(str)
char *str;
{
if (DEBUG)
fprintf(LOGFP,"DEBUG: '%s'\n",str);
}
Robert Perlberg
Resource Dynamics Inc.
New York
philabs!rdin!rdin2!perl