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