home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-02-04 | 44.6 KB | 1,601 lines |
- /*
- * A completely new C Kermit module.
- *
- * Based on code from Frank Da Cruz's excellent book, _Kermit: A File
- * Transfer Protocol_, Digital Press, 1986.
- *
- * As this code is almost entirely from said book, it is certainly covered
- * by that book's copyright. Basically, this means the code is freely
- * distributable, and can be used in a commercial program provided such
- * use does not increase the program's cost to the purchaser beyond a small
- * handling fee.
- *
- * Stephen Walton, swalton@solar.stanford.edu
- * Dept. of Physics and Astronomy
- * California State University, Northridge
- * Northridge, CA 91330
- *
- * ORGANIZATION
- *
- * This file is in three pieces, and could probably be broken into
- * two files. Leading off are #DEFINE's and declarations of
- * global and external variables. Following are the unmodified sources
- * from The Book. Then are the z* file-handling routines written using
- * standard Unix-style (almost ANSI C) file routines.
- *
- * I make no apologies for the organization; my primary goals were (1) to
- * use the unmodified book source except for errors found by Lint, and
- * (2) to allow this file to be plugged into an otherwise unmodified
- * terminal program for the Commodore Amiga computer called VT100. The
- * comments starting with the string "/*lint" are for the Lint program
- * of Gimpel Software, available for the Commodore Amiga and MS-DOS
- * machines. I highly recommend it.
- *
- * A few words about style herein. Both "book Kermit" and the official
- * C Kermit release make extensive use of global variables to set various
- * options and keep track of what is going on. I don't like this, but
- * since example source code must be part of the Kermit specification,
- * I chose to keep that organization. There are several places where I
- * I have tried to modularize things better. First of all, everything
- * which is not needed outside of this file is declared "static". Second,
- * I have kept the book Kermit code pretty much intact, except for some lint
- * related things and one extra convention: tmsg() appends characters to
- * an existing status line, but tmsgl() is required to force that output to
- * be seen. Hence, I've changed the last in each series of tmsg() calls to
- * tmsgl().
- */
-
-
- /*
- * Revision History--Versions 0 through 1 never left me.
- *
- * Version 0.5--Created and linted.
- * Version 0.6--Added RESUME to handling of "unknown packets".
- * --Added proto() function to wrap around wart() for handling
- * of startup and cleanup functions.
- * --Changed handling of timeouts in input(): instead of an
- * error("Timeout") call, it puts the "Timeout" message in
- * the data field and pretends it read an 'E' packet.
- * Version 0.7--Fixed a problem with rpsiz and MAXRP. I had set rpsiz
- * to MAXRP in rpar() and was calling ttinl() with a max
- * argument of MAXRP, which resulted in truncated packets;
- * to wit, MAXRP+1 characters could come into ttinl counting
- * the eol. Created defines DRPSIZ/DSPSIZ for default values
- * for rpsiz and spsiz, and increased MAXRP.
- * --Changed rcvpkt, sndpkt, and data so that they are pointers
- * instead of static arrays, and allocate and de-allocate
- * them in proto().
- * Version 0.8--Added client support. To make a Get
- * command, point the char *cmarg at the remote file
- * specification and set the start state to 'r'
- * (extern char start in the calling file).
- * Version 0.9--Added long packet support. This required adding an extern
- * int urpsiz which is set to the desired receive packet size
- * by the user interface.
- * --Since the above required using the capas, I also added the
- * code from C Kermit 4E(070) for negotiating window size
- * in rpar() and spar(). Of course, we don't do windows yet.
- * --Fixed a bug which is also part of C Kermit 4E(070).
- * If we tell the sender that we can receive a packet
- * of size MAXRP, the packet can contain as many as
- * MAXRP+5 characters, counting the EOL and extended
- * headers. So rpack() must be able to handle somewhat
- * more characters than the actual maximum packet length.
- * I defined MAXRP here to be 1024, but only allow
- * rpsiz in proto() to be MAXRP-20.
- * Version 0.95--Added code to gracefully abort transfer. This works
- * via the cx and cz external variables and the state 'a'.
- * Version 1.0--Unleashed upon the world.
- * Version 1.1--Marco Papa (papa on BIX, papa@pollux.usc.edu on Internet)
- * added the code between the #ifdef XPRKERMIT...#endif
- * pairs, which turns this code into a routine which can
- * be used as an Amiga external file transfer protocol.
- * Upon getting it back from him, I fixed two lingering
- * bugs: there was an "if (ebqflg & b8)" in encode()
- * which should be &&, and the first argument of encode()
- * needed to be declared as an int, not a char.
- * --Allow user to set bctr (block check to request) himself.
- * --If urpsiz is illegal, we set rpsiz to a legal value; I also
- * set urpsiz to this as well, so the user knows what's up.
- * Version 1.2--Added a typedef of CHAR to unsigned char to allow this code
- * to work with the latest version of Wart (V 1A(006) dated
- * 12 January 1989.
- * Version 1.3--21 December 1989
- * (1) Added a tflush() call to the end of decode(). This
- * gives the user an opportunity to flush out the messages
- * from X packets, if the I/O is buffered.
- *
- * Version 1.4-- 5 January 1989
- * (1) Added the counters for characters on a per-file and
- * per-transaction basis. Later, we can use the per-file
- * ones and a timer to figure out how long we have to go
- * on the current file.
- * (2) Started replacing tchar() calls with calls to the
- * screen() function, again a la C Kermit. #define's for
- * the manifest constants for screen() are in kermitproto.h,
- * copied from C Kermit.
- *
- */
-
- #ifdef XPRKERMIT
- extern long calla(), callaa(), callad(), calladd(), calladda(), calldaa();
- extern long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(),
- (*xfwrite)(), (*xsread)(), (*xchkabort)(), (*xffirst)(), (*xfnext)(),
- (*xsflush)(), (*xfinfo)(), (*xgets)();
- extern long brkflag;
- #include "types.h"
- #include "xproto.h"
- #endif
-
- /*
- * Run this through the Wart preprocessor which comes with C Kermit.
- */
-
- #include "kermitproto.h"
-
- /*
- * Here are the variables which need to be set to startup values, and which
- * also can be freely changed between protocol transfers. At first I thought
- * to declare them all "extern" in order to force definition elsewhere.
- * On reflection, it makes sense to both declare them here and set them to
- * their default startup values. Thus they can be ignored outside of this
- * module if you so desire.
- *
- * Note that the names are very systematic: Names beginning with "r" have
- * to do with values I use for received packets; those beginning with "s"
- * are values I use for sending packets. Also note we set some, others are
- * set for us. I have made the ones we get in spar() static (local),
- * and the ones we send in rpar() global.
- *
- * First the ints.
- */
-
- int cx = 0,
- cz = 0, /* Flags for aborting transfers. cx (control-X)*
- * is set to 1 if an abort of the current file *
- * is desired, cz (control-Z) if an abort of *
- * an entire batch transfer is desired. */
- rpsiz = MAXRP, /* Maximum packet size */
- /* Like most of the receive packet parameters, *
- * this one is actually set by the sender. But *
- * since the sender has the option to not send *
- * these, we must initialize to "reasonable" *
- * defaults. */
- bctr = 1, /* Block check type to request. */
- limit = 5, /* Retry limit on receive */
- warn = 0, /* 1 for warn before overwriting files */
- rpadn = 0, /* Number of pad characters I require. */
- rtimo = 10; /* How long I want you to wait before you *
- * you time me out. */
-
- char rmark = '\1', /* Start of packet marker for receive */
- reol = '\r', /* End of packet marker for receive */
- start = 0, /* Start state */
- sctlq = '#', /* Control character quote character for send */
- rpadc = '\0'; /* Pad character I want you to use */
-
- /*
- * Variables which MUST be set by the external interface.
- */
- extern int
- parity, /* 0 for no parity--need for proper 8th-bit quote */
- text, /* Flag 1 for text file, 0 for binary file */
- urpsiz; /* Maximum receive packet size user wants. */
-
- extern char
- *cmarg; /* Character string containing Kermit server cmd */
-
- /*
- * Variables having to do with the status of the file transfer.
- */
- static long tfc, /* File chararacters sent/received, total. */
- ffc, /* " " " , current file. */
- tlci, /* Comm line characters in, total. */
- flci, /* " " " ", current file. */
- tlco, /* " " " ", total. */
- flco; /* " " " ", current file. */
- /*
- * In a fit of cleverness, here are some macro defines for variables we *
- * aren't currently using. Only now we tell Lint to ignore constant *
- * Booleans!
- */
-
- /*lint -e506 */
-
- #define local 1 /* Local mode flag--that is, I'm on your end */
- #define server 0 /* We are never server */
- #define delay 0 /* Time to delay before sending first packet */
- #define xpkt 0 /* Send X packet instead of F? */
-
- /*
- * This block of defines is strictly internal flags of various kinds. *
- * I hope to Grid that I've got them all. Someday this will be cleaner *
- */
- static int
- spsiz = DSPSIZ, /* Maximum send packet size */
- wsize = MAXWS, /* Maximum window size */
- sndpkl, /* Size of packet currently being attempted */
- filcnt, /* Number of files transferred so far */
- bctu = 1, /* Block check type to use */
- rqf, /* Flag for 8th bit quote negotiations */
- ebq = '&', /* 8th-bit prefix */
- ebqflg = 0, /* 8th-bit quoting flag */
- xflag, /* Output to screen for generic server commands */
- rq = 0, /* Received 8bq bid */
- sq = 'Y', /* Sent 8bq bid */
- rpt = 0, /* Repeat count */
- rptq = '~', /* Repeat prefix */
- rptflg = 0, /* Repeat processing flag */
- capas = 10, /* Final position of inbound capas mask */
- atcapr = 0, /* Attribute capability requested */
- atcapu = 0, /* Attribute capability used */
- swcapr = 0, /* Sliding windows capability requested */
- swcapu = 0, /* Sliding windows capability used */
- lpcapr = 0, /* Long packets capability requested */
- lpcapu = 0, /* Long packets capability used */
- rsn, /* Received sequence number */
- seq = 0, /* Current sequence number */
- maxsiz, /* Maximum data size for packet */
- rln, /* Length of received data field */
- size, /* Current size of output packet data */
- osize, /* Previous output packet data size */
- first = 0, /* Some kind of lookahead flag */
- stimo = 5, /* Timeout interval for me to use */
- spadn = 0; /* Number of pad characters for me to use */
-
- #define atcapb 8 /* Attribute capability bit */
- #define swcapb 4 /* Sliding windows capability bit */
- #define lpcapb 2 /* Long packets capability bit */
- #define closif zclosi /* I use closif() to close the input file in *
- * case it needs to be more complex later, but *
- * for now it just calls the z routine. */
-
- static char
- smark = '\1', /* Start of packet marker for send */
- spadc = '\0', /* Pad character to use on sending */
- seol = '\r', /* End of packet marker for sending */
- rctlq = '#', /* Control character quote char for receiving */
- filnam[50], /* Current file name */
- ssc, /* Start server command */
- *sndpkt, /* Send packet. */
- *rcvpkt, /* Receieve packet. */
- *data, /* Data to send/receive before encode/decode */
- *rdatap, /* Pointer to null-terminated data field */
- *isp = NULL, /* Pointer to characters in memory */
- *osp = NULL; /* Output string pointer */
-
- /*
- * Forward declarations. Soon to be prototypes if the ANSI standard
- * committee keeps its promises.
- */
- int input(), spack(), ack();
- char *rpar();
-
- /*
- * External routines provided.
- */
-
- extern int ttinl(), ttol(), gnfile();
- #ifdef XPRKERMIT
- extern void ttflui(), tchar(), sleep();
- #else
- extern void ttflui(), tchar(), tmsg(), tmsgl(), sleep();
- #endif
- #define ERR(s) error(s); RESUME
- #define RESUME return
-
- /*lint -save -e525 -e527 We don't care how Wart formats! */
-
- %states ssfil ssdat sseot
- %states srini srfil srdat
- %states sipkt srgen
- %%
-
- /* Start states */
-
- s { /* - Start State - */
- tinit(); /* Initialize transaction */
- if (sinit('S') < 0) { ERR("sinit"); } /* Build, send Send-Init. */
- else { /* If successful, */
- filcnt = 0; /* initialize file counter */
- BEGIN ssfil; /* and switch to ssfil state. */
- }
- }
- v { tinit(); rinit(); BEGIN srini; } /* - Receive - */
-
- r { /* Get */
- tinit(); ssc = 0;
- if (sinit('I') < 0) { ERR("sinit"); }
- else BEGIN sipkt;
- }
-
- c { /* Host */
- tinit(); ssc = 'C';
- if (sinit('I') < 0) { ERR("sinit"); }
- else BEGIN sipkt;
- }
-
- g { /* Generic */
- tinit(); ssc = 'G';
- if (sinit('I') < 0) { ERR("sinit"); }
- else BEGIN sipkt;
- }
-
- a { /* Immediate protocol abort */
- spack('E', seq, 21, "User aborted protocol");
- closif(); closof(1); /* Close files, deleting output */
- RESUME;
- }
-
- /* Dynamic states, sending file(s) */
-
- <ssfil>Y { /* - Send File State - */
- if (filcnt++ == 0) spar(rdatap); /* Set parameters if 1st time */
- cx = 0; /* Reset file interruption flag */
- bctu = bctr; /* Switch to negotiated block check */
- resetc(); /* Reset global counters. */
- #ifdef XPRKERMIT
- ST_Display_CRC(bctu);
- #endif
- /* Is there a file to send in an uncancelled batch? */
- if (!cz && gnfile(filnam, sizeof(filnam)) > 0) {
- if (sfile() < 0) { ERR("sfile"); } /* Yes, open it, send F packet */
- else BEGIN ssdat; /* and if no error, switch state. */
- } else { /* No (more) files to send */
- if (seot() < 0) { ERR("seot"); } /* so send B packet */
- else BEGIN sseot; /* and switch to sseot state. */
- }
- }
- <ssdat>Y { /* - Send Data State - */
- int x;
- if (rln == 1 && *rdatap == 'X') /* Did ACK contain X as data? */
- cx = 1; /* Yes, set control-x flag. */
- else if (rln == 1 && *rdatap == 'Z') /* Did ACK contain Z as data? */
- cz = 1; /* Yes set control-z flag. */
- /* Check here for cancellation of transfer and data left to send. */
- if (cx || cz || (x = sdata()) == 0) {
- if (seof((cx | cz) ? "D" : "") < 0) { /* If not, send Z packet. */
- ERR("seof");
- }
- else BEGIN ssfil; /* and go back to ssfil state. */
- } else if (x < 0) { ERR("sdata"); } /* Handle file i/o errors. */
- }
- <sseot>Y { RESUME; } /* - Send B, done. */
-
- /* Dynamic states, receiving file(s) */
-
- <srini,srgen>S {
- resetc();
- spar(rdatap);
- (void) ack1(rpar());
- bctu = bctr;
- BEGIN srfil;
- }
-
- <srfil>B { (void) ack(); RESUME; }
-
- <srfil>F { if (rcvfil() < 0) { ERR("rcvfil"); } else { (void) ack(); BEGIN srdat; } }
-
- <srdat>D {
- if (cx)
- ack1("X");
- else if (cz)
- ack1("Z");
- else {
- if (decode() < 0) { ERR("decode"); } else (void) ack();
- }
- }
-
- <srdat>Z {
- /* Discard output file if the sender tells us so. */
- if (closof(cx || cz || (rln == 1 && *rdatap == 'D')) < 0) {
- ERR("error closing file");
- } else {
- (void) ack(); BEGIN srfil;
- }
- }
-
- /* Dynamic states, server mode */
-
- <sipkt>Y { /* Got ACK for I packet */
- spar(rdatap); /* Set parameters from it */
- start = 'E'; /* Force entry into next state */
- }
-
- <sipkt>E { /* Got E for I packet */
- if (ssc) {
- if (scmd(ssc,cmarg) < 0) { ERR("scmd"); }
- else BEGIN srgen;
- } else {
- if (scmd('R',cmarg) < 0) { ERR("scmd"); }
- else BEGIN srini;
- }
- }
-
- <srgen>Y { xflag = 1; decode(); RESUME; }
-
- <srgen,srfil>X { xflag = 1; ack(); BEGIN srdat; }
-
- /* Error state */
-
- E { error(rdatap);
- (void) closif();
- (void) closof(1); /* close files, discarding output */
- RESUME; }
-
- . { error("Unexpected packet type"); RESUME; }
- /* Handle unwanted packet types. */
- %%
-
- /*lint -restore */
-
- static
- int
- input() { /* Return packets */
- int type, try;
-
- if (start != 0) { /* Start state in effect? */
- type = start; /* Yes, call it a packet type, */
- start = 0; /* nullify the start state, */
- return(type); /* and return the type. */
- }
- type = rpack(); /* No start state, read a packet. */
- for (try = 0; rsn != seq || strchr("TQN",type); try++) {
- if (try > limit) { /* If too mahy tries, */
- strcpy(data, "Timed out"); /* give up */
- rdatap = data; /* Make up pretend 'E' packet */
- return('E'); /* and return it */
- }
- if (type == 'N' && rsn == ((seq + 1) & 63)) {
- /* NAK for next packet */
- return('Y'); /* is ACK for current. */
- } else { /* Otherwise, */
- (void) resend(); /* resend previous packet. */
- }
- type = rpack(); /* Try to read response. */
- }
- ttflui(); /* Got a good one, clear buffer. */
- return(type); /* Return its type. */
- }
-
- static
- nxtpkt() {
- seq = (seq + 1) & 63; /* Next packet number, mod 64 */
- }
-
- /* R E S E T C -- Reset per-transaction character counters */
- resetc() {
- tfc = tlci = tlco = 0; /* Total file chars, line chars in & out */
- }
-
- static
- tinit() { /* Transaction initialization */
- seq = 0; /* Start off with packet 0 */
- ebqflg = 0; /* 8-bit quoting off */
- sq = 'Y'; /* Normal 8-bit quote bid */
- rqf = -1; /* Flag other's bid not yet seen */
- rptflg = 0; /* No repeat counts by default */
- bctu = 1; /* Block check to use back to 1 */
- xflag = 0; /* Output normally to file */
- osp = NULL; /* ... */
- *filnam = *sndpkt = *rcvpkt = '\0'; /* Clear string buffers */
- }
-
- static
- error(s) char *s; { /* Fatal error */
- if (local) { /* If in local mode */
- screen(SCR_EM,0,0L,s); /* Type message on console */
- } else { /* Otherwise, */
- (void) spack('E',seq,strlen(s),s); /* Send in error packet. */
- }
- return;
- }
-
- static
- ack() {
- int x; /* Empty acknowledgement */
- x = spack('Y',seq,0,""); /* Send the packet */
- nxtpkt(); /* Increment the packet number */
- return(x);
- }
-
- static
- ack1(s) char *s; {
- int x; /* Acknowledgement with data */
- x = spack('Y',seq,strlen(s),s); /* Send the packet */
- nxtpkt(); /* Increment packet number */
- return(x);
- }
-
- static
- nak() { /* Negative acknowledgement */
- return(spack('N',seq,0,"")); /* Never has data! */
- }
-
- /* Functions used by file sender. */
-
- /* sinit()--start the transaction by filling in the initialization string
- * and sending it in an S packet.
- */
-
- static
- sinit(c) char c; {
- char *s;
- s = rpar();
- if (local == 0 && c == 'S' && server == 0) {
- #ifdef XPRKERMIT
- ST_Display_String(STMsg,"Escape back to local system, RECEIVE command");
- #else
- tmsgl("Escape back to local system, give RECEIVE command...");
- #endif
- sleep(delay);
- }
- return(spack(c,seq,strlen(s),s));
- }
-
- /*
- * scmd() -- send a preformatted Kermit server command string.
- */
- static
- scmd(t, s) char t, *s; { /* Send a packet of the given type */
- encstr(s); /* Encode the command string */
- spack(t,seq,size,data);
- }
-
- /* rinit() -- do whatever is needed to initialize receive. Now a no-op.
- */
- static
- rinit()
- {
- }
-
- /* sfile() -- open the file and send the File-Header packet. Assumes that
- * the global string pointer filnam references the file name.
- */
-
- static
- sfile() {
- int x;
- char pktnam[50];
- if (zopeni(filnam) < 0) /* Try to open file. */
- return -1;
- zltor(filnam,pktnam); /* OK, convert name. */
- x = encstr(pktnam); /* Encode the result */
- if (local) { /* If in local mode, */
- #ifdef XPRKERMIT
- ST_Display_String(STFile, pktnam);
- ST_Display_String(STUplSize, filnam);
- #else
- tmsg("Sending "); /* let user know we're */
- tmsg(filnam); /* sending this file */
- tmsg(" as "); /* under */
- tmsgl(pktnam); /* this name */
- #endif
- }
- first = 1; /* Flag beginning of file */
- ffc = flci = flco = 0; /* Zero per-file char count */
- maxsiz = spsiz - (bctr + 3); /* Maximum data length */
- nxtpkt(); /* Increment packet number */
- return(spack((xpkt ? 'X' : 'F'),seq,x,data)); /* Send packet */
- }
-
- /* sdata() -- get next packet's worth of data */
-
- static
- sdata() {
- int x;
- if ((x = getpkt(maxsiz)) == 0) /* If no data left to send, */
- return(0); /* return EOF indication. */
- nxtpkt();
- return(spack('D',seq,x,data)); /* Send the data packet */
- }
-
- /* seof -- close the input file and send a Z packet. */
-
- static
- seof(s) char *s; {
- if (closif() < 0) /* Try to close the file. */
- return -1; /* On error, return failure. */
- else { /* Otherwise, */
- #ifdef XPRKERMIT
- if (local) ST_Display_String(STMsg,"OK");
- #else
- if (local) tmsgl("OK"); /* if local, reassure user. */
- #endif
- nxtpkt();
- return(spack('Z',seq,strlen(s),s)); /* Send Z packet */
- }
- }
-
- /* seot -- send B packet. */
-
- static
- seot() {
- nxtpkt();
- #ifdef XPRKERMIT
- if (local) ST_Display_String(STMsg,"Done");
- #else
- if (local) tmsgl("Done");
- #endif
- return(spack('B',seq,0,""));
- }
-
- static
- rcvfil() { /* Receive a file */
- char myname[50];
-
- ffc = flci = flco = 0; /* Initialize per-file char count */
- decstr(filnam); /* Decode name */
- zrtol(filnam,myname,warn); /* Convert to local form. */
- if (zopeno(myname) < 0)
- return -1;
- else { /* File open OK, give message. */
- if (local && !xflag) {
- #ifdef XPRKERMIT
- ST_Display_String(STFile,myname);
- ST_Display_CRC(bctu);
- #else
- tmsg("Receiving "); tmsg(filnam); tmsg(" as "); tmsgl(myname);
- #endif
- }
- return 0;
- }
- }
-
- static
- closof(nokeep) int nokeep; { /* Close output file, but */
- if (xflag) return 0; /* not if it's the screen. */
- if (zcloso(nokeep) < 0)
- return -1;
- return 0;
- }
-
- static
- spack(type,n,len,d) char type, *d; int n, len; {
- int i = 0, j, k;
- char *sohp; /* Mark start of packet data. */
-
- for (i = 0; i < spadn; i++)
- sndpkt[i] = spadc; /* Do requested padding */
- sohp = sndpkt + i;
- sndpkt[i++] = smark; /* Packet mark */
- k = i++; /* Remember this place */
- sndpkt[i++] = tochar(n); /* Sequence number */
- sndpkt[i++] = type; /* Packet type */
- j = len + bctu; /* True length */
- if (j > 95) { /* Long packet? */
- sndpkt[k] = tochar(0); /* Set LEN to 0 */
- sndpkt[i++] = tochar(j / 95); /* High part of length */
- sndpkt[i++] = tochar(j % 95); /* Low part of length */
- sndpkt[i] = '\0'; /* Header checksum */
- sndpkt[i++] = tochar(chk1(sndpkt+k));
- } else
- sndpkt[k] = tochar(j+2); /* True length. */
-
- for (j = len; j > 0; j--) { /* Data */
- sndpkt[i++] = *d++;
- }
- sndpkt[i] = '\0'; /* Null terminate. */
- switch (bctu) {
- case 1: /* Type 1 - 6 bit checksum */
- sndpkt[i++] = tochar(chk1(sndpkt+k));
- break;
- case 2: /* Type 2 - 12 bit checksum */
- j = chksum(sndpkt+k);
- sndpkt[i++] = tochar((j >> 6) & 077);
- sndpkt[i++] = tochar(j & 077);
- break;
- case 3: /* Type 3 - 16 bit CRC-CCITT */
- j = chk3(sndpkt + k);
- sndpkt[i++] = tochar((j >> 12) & 017);
- sndpkt[i++] = tochar((j >> 6) & 077);
- sndpkt[i++] = tochar(j & 077);
- break;
- }
- sndpkt[i++] = seol; /* End of line */
- sndpkt[i] = '\0'; /* Null string-terminat or. */
- sndpkl = i; /* Remember length. */
- i = ttol(sndpkt,sndpkl); /* Send the packet. */
- tlco += sndpkl; /* Count characters output. */
- flco += sndpkl;
- screen(SCR_PT, type, (long) n, sohp);
- return(i);
- }
-
- static
- resend() {
- int x;
- if (*sndpkt)
- x = ttol(sndpkt,sndpkl); /* Send previous packet */
- else
- x = nak(); /* or NAK if none */
- if (local && !xflag) tchar('%'); /* Let the user know. */
- return(x);
- }
-
- chk1(packet) char *packet; { /* Compute Kermit's */
- int s, t; /* 1-character block check. */
- s = chksum(packet); /* Get the arithmetic sum. */
- t = (((s & 192) >> 6) + s) & 63; /* Fold it into 6 bits. */
- return(t);
- }
-
- static
- chksum(p) char *p; { /* Compute the checksum. */
- unsigned m;
- long s;
-
- m = (parity) ? 0177 : 0377; /* Mask for parity bit. */
- s = 0;
- for (; *p != '\0'; p++) /* For each character, */
- s += *p & m; /* accumulate the sum, */
- return(s & 07777); /* and then return it. */
- }
-
- /*
- * rpack reads a packet and returns the packet type, or else Q if the
- * packet was invalid, or T if a timeout occured. Upon successful return,
- * sets the global variables:
- * rsn - the received sequence number
- * rln - length of the received data field
- * rdatap - a pointer to the null-terminated contents of the data field
- */
- static
- rpack() {
- int i, j, x, type, rlnpos;
- char pbc[4]; /* Packet block check. */
- char *sohp; /* Start of packet data. */
-
- rsn = rln = -1; /* In case of failure. */
-
- *rcvpkt = '\0'; /* Initialize receive buffer. */
- j = ttinl(rcvpkt,MAXRP,reol,stimo); /* Try to get a "line". */
- if (j < 0) return('T'); /* Timed out. */
-
- tlci += j; /* Count received characters. */
- flci += j; /* On per-file basis. */
- for (i = 0; rcvpkt[i] != rmark && (i < j); i++) /* Find mark. */
- ;
- if (i == j) return('Q'); /* If no mark, bad packet. */
- sohp = rcvpkt+i;
-
- rlnpos = ++i; /* Got it, remember position. */
- if ((j = unchar(rcvpkt[i++])) == 0) { /* Long packet? */
- j = rlnpos + 5; /* Yes, check header */
- if (j > MAXRP) return('Q'); /* Be defensive. */
- x = rcvpkt[j]; /* Remember header checksum */
- rcvpkt[j] = '\0';
- if (unchar(x) != chk1(rcvpkt+rlnpos)) /* Check header */
- return('Q');
- rcvpkt[j] = x; /* Restore packet */
- rln = unchar(rcvpkt[j-2]) * 95 + unchar(rcvpkt[j-1]) - bctu;
- j = 3;
- } else {
- rln = j - bctu - 2; /* Regular packet */
- j = 0; /* No extended header */
- }
- rsn = unchar(rcvpkt[i++]); /* Sequence number. */
- type = rcvpkt[i++]; /* Packet type */
- i += j; /* Skip extended header, if any */
- rdatap = rcvpkt + i; /* The data itself. */
- j = rln + i; /* Position of block check. */
- if (j > MAXRP)
- return('Q'); /* Be defensive! */
- for (x = 0; x < bctu; x++) /* Copy the block check. */
- pbc[x] = rcvpkt[j+x];
- rcvpkt[j] = '\0';
- switch (bctu) { /* Which block check type? */
- case 1:
- if (unchar(*pbc) != chk1(rcvpkt+rlnpos)) return('Q');
- break;
- case 2:
- x = unchar(*pbc) << 6 | unchar(pbc[1]);
- if (x != chksum(rcvpkt+rlnpos)) return('Q');
- case 3:
- x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]);
- if (x != chk3(rcvpkt+rlnpos)) return('Q');
- break;
- default:
- error("Impossible block check type.");
- }
- screen(SCR_PT, type, (long) rsn, sohp);
- return type; /* Otherwise, return packet type */
- }
-
- /*
- * CHK3
- * Calculate the 16-bit CRC of a null-terminated string using a
- * byte-oriented tableless algorithm devised by Andy Lowry (Columbia
- * University). The magic number 010201 is derived from the CRC-CCITT
- * polynomial x^16+x^12+x^5+1.
- */
- static
- chk3(s) char *s; {
- unsigned int c, q;
- long crc = 0;
-
- while ((c = *s++) != '\0') {
- if (parity) c &= 0177;
- q = (crc ^ c) & 017; /* Low order nybble */
- crc = (crc >> 4) ^ (q * 010201);
- q = (crc ^ (c >> 4)) & 017; /* High order nybble */
- crc = (crc >> 4) ^ (q * 010201);
- }
- return(crc);
- }
-
- /*
- * getpkt--Fill a packet to the maximum. Result goes in local data array
- * whose current length is indicated in global size.
- */
- static
- getpkt(maxlen) int maxlen; {
- int i, next;
- static int c;
- static char remain[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
- void encode();
-
- if (first == 1) { /* If first time thru... */
- first = 0; /* remember not to do this next time, */
- remain[0] = '\0'; /* discard any old leftovers, */
- c = gnchar(); /* get first character of file */
- if (c < 0) { /* watching out for null file */
- first = -1;
- return(size = 0);
- }
- } else if (first == -1) { /* EOF from last time? */
- return(size = 0);
- }
-
-
- /* Copy any leftovers that didn't fit in the last packet. */
-
- for (size = 0; (data[size] = remain[size]) != '\0'; size++)
- ;
- *remain = '\0';
-
- /* Get, encode, and deposit the next character. */
-
- rpt = 0; /* Initialize repeat counter. */
-
- while (first > -1) { /* Until end of file or string... */
- next = gnchar(); /* Look ahead one character */
- if (next < 0) first = -1; /* If none, we're at EOF. */
- osize = size; /* Remember current size. */
- encode(c, next); /* Encode the character. */
- c = next; /* Old next char is now current. */
- if (size == maxlen) return(size); /* If just at end, done. */
- if (size > maxlen) { /* Past end, must save some. */
- for (i = 0; (remain[i] = data[osize+i]) != '\0'; i++)
- ;
- size = osize;
- data[size] = '\0';
- return(size); /* Return size. */
- }
- }
- return(size); /* EOF, return size. */
- }
-
- static
- gnchar() {
- int c;
-
- if (isp) { /* From string in memory */
- return((c = *isp++) > 0 ? c : -1);
- } else {
- if ((c = zgetc(text)) > 0) { /* or from a file. */
- ffc++; tfc++;
- }
- return c;
- }
- }
-
- /*
- * Encodes the character a into the global data array,
- * and the global size is updated.
- * Global sctlq is the control prefix for sending data.
- *
- * The first argument is spec'd as a char in the Kermit book but must
- * actually be an int; otherwise, it is sign extended and the comparison
- * if (a == next) comes up TRUE if the last character in the file has the
- * value 255 and the EOF flag (which is what next's value will be in this
- * case) is -1. This results in that last 255 not being sent.
- */
- static void
- encode(a, next) int a; int next; {
- int a7, b8;
-
- if (rptflg) { /* Doing run-length encoding? */
- if (a == next) { /* Yes, got a run? */
- if (++rpt < 94) { /* Yes count. */
- return;
- } else if (rpt == 94) { /* If at maximum */
- data[size++] = rptq; /* Emit prefix, */
- data[size++] = tochar(rpt); /* and count, */
- rpt = 0; /* and reset counter. */
- }
- } else if (rpt == 1) { /* Run broken, only two? */
- rpt = 0; /* Yes, do the character wice */
- encode(a,-1); /* by calling self recursively. */
- if (size <= maxsiz) osize = size; /* Watch for boundary */
- rpt = 0; /* Call self second time. */
- encode(a,-1);
- return;
- } else if (rpt > 1) { /* Run broken, more than two? */
- data[size++] = rptq; /* Yes, emit prefix and count */
- data[size++] = tochar(++rpt);
- rpt = 0; /* and reset counter. */
- }
- }
- a7 = a & 127; /* Isolate low 7 bits */
- b8 = a & 128; /* And "parity" bit */
-
- if (ebqflg && b8) { /* If doing 8th-bit prefixing */
- data[size++] = ebq; /* and 8th bit on, insert prefix */
- a = a7; /* and clear the 8th bit. */
- }
- if (a7 < 32 || a7 == 127) { /* If control character */
- data[size++] = sctlq; /* insert control quote */
- a = ctl(a); /* and make printable. */
- } else if (a7 == sctlq) /* If data is control prefix, */
- data[size++] = sctlq; /* prefix it. */
- else if (ebqflg && a7 == ebq) /* If doing 8th-bit prefixing, */
- data[size++] = sctlq; /* ditto for 8th-bit prefix. */
- else if (rptflg && a7 == rptq) /* If doing run-length encoding, */
- data[size++] = sctlq; /* ditto for repeat prefix. */
-
- data[size++] = a; /* Finally, emit the character. */
- data[size] = '\0'; /* Terminate string. */
- }
-
- /*
- * Decodes the data pointed to by the global pointer rdatap.
- */
- static
- decode() {
- int a, a7, b8;
-
- while ((a = *rdatap++) != '\0') {
- rpt = 1; /* Initialize repeat count. */
- if (rptflg) { /* Repeat processing? */
- if (a == rptq) { /* Yes, have repat prefix? */
- rpt = unchar(*rdatap++); /* Yes, get count. */
- a = *rdatap++; /* and following character. */
- }
- }
- b8 = 0; /* Assume 8th bit not on. */
- if (ebqflg) { /* Doing 8th-bit prefixing? */
- if (a == ebq) { /* Yes, have 8th-bit prefix? */
- b8 = 128; /* Yes, remember bit 8 on */
- a = *rdatap++; /* and get following character. */
- }
- }
- if (a == rctlq) { /* Is it control prefix? */
- a = *rdatap++; /* Yes, get next character */
- a7 = a & 127; /* and its low 7 bits. */
- if (a7 > 62 && a7 < 96) /* Encoded control character? */
- a = ctl(a); /* Yes, controllify */
- }
- a |= b8; /* OR in the 8th bit. */
- for (; rpt > 0; rpt--) {
- if (pnchar(a) < 0) return -1; /* Output the character. */
- ffc++; tfc++; /* Update character counts. */
- }
- }
- tflush(); /* Flush out message (if xflag) */
- return(0);
- }
-
- static
- pnchar(c) int c; { /* Put next character. */
- if (xflag) { /* To screen if desired. */
- tchar(c);
- return(1);
- } else if (osp) { /* Or to string in memory... */
- *osp++ = c;
- return(1);
- } else return(zputc(c,text)); /* Otherwise to file. */
- }
-
- static
- encstr(s) char *s; { /* Fill a packet from the string */
- first = 1; /* Start lookahead. */
- isp = s; /* Set input string pointer */
- (void) getpkt(spsiz); /* Fill a packet */
- isp = NULL; /* Reset input string pointer */
- return(size); /* Return data field length */
- }
-
- static
- decstr(s) char *s; { /* Decode packet data into a string */
- osp = s; /* Set output string pointer */
- (void) decode(); /* Decode the string */
- *osp = '\0'; /* Terminate the string */
- osp = NULL; /* Reset output string pointer */
- }
-
- static
- spar(s) char *s; { /* Set parameters */
- int x;
-
- s--; /* Line up with field numbers. */
-
- /* Limit on size of outbound packets */
- x = (rln >= 1) ? unchar(s[1]) : 80;
- spsiz = (x < 10) ? 80 : x;
-
- /* Timeout on inbound packets */
- x = (rln >= 2) ? unchar(s[2]) : 5;
- stimo = (x < 0) ? 5 : x;
-
-
- /* Outbound padding */
- spadn = 0; spadc = '\0';
- if (rln >= 3) {
- spadn = unchar(s[3]);
- if (rln >= 4)
- spadc = ctl(s[4]);
- }
-
- /* Outbound packet terminator */
- seol = (rln >= 5) ? unchar(s[5]) : '\r';
- if (seol < 2 || seol > 31) seol = '\r';
-
- /* Control prefix */
- x = (rln >= 6) ? s[6] : '#';
- rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
-
- /* 8th-bit quoting */
- rq = (rln >= 7) ? s[7] : 0;
- if (rq == 'Y') rqf = 1;
- else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
- else rqf = 0;
-
- switch (rqf) {
- case 0: ebqflg = 0; break;
- case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
- case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
- }
-
- /* Block check */
- x = 1;
- if (rln >= 8) {
- x = s[8] - '0';
- if (x < 1 || x > 3) x = 1;
- }
- bctr = x;
-
- /* Repeat prefix */
- if (rln >= 9) {
- rptq = s[9];
- rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
- } else rptflg = 0;
-
- /* Capabilities */
- atcapu = lpcapu = swcapu = 0; /* No capabilities by default */
- if (rln >= 10) {
- x = unchar(s[10]);
- atcapu = (x & atcapb) && atcapr; /* Attribute packets */
- lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
- swcapu = (x & swcapb) && swcapr; /* Sliding windows */
- for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++)
- ; /* Skip to capas + 1 */
- }
-
- /* Long packets */
- if (lpcapu) { /* Flag set above */
- if (rln > capas+2) {
- x = unchar(s[capas+2]) * 95 + unchar(s[capas+3]);
- spsiz = x > MAXSP ? MAXSP : x;
- }
- /* else a fatal error, but how do we terminate? */
- }
-
- /* Sliding windows */
- if (swcapu) {
- if (rln > capas+1) {
- x = unchar(s[capas+1]);
- wsize = x > MAXWS ? MAXWS : x;
- } else
- wsize = 1;
- }
- }
-
- /* Fill the array with my send-init parameters */
-
- static char *
- rpar() {
- data[1] = tochar(DRPSIZ); /* Biggest packet I can receive */
- data[2] = tochar(rtimo); /* When I want to be timed out */
- data[3] = tochar(rpadn); /* How much padding I need */
- data[4] = ctl(rpadc); /* Padding character I want */
- data[5] = tochar(reol); /* End-of-Line character I want */
- data[6] = sctlq; /* Control-Quote character I send */
- switch(rqf) { /* 8th-bit prefix */
- case -1:
- case 1: if (parity) ebq = sq = '&'; break;
- case 0:
- case 2: break;
- }
- data[7] = sq;
- data[8] = bctr + '0'; /* Block Check Type */
- if (rptflg) data[9] = rptq; else data[9] = '~';
- data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0);
- capas = 10;
- data[capas+1] = tochar(swcapr ? wsize : 0); /* Window size */
- data[capas+2] = tochar(rpsiz / 95); /* Long packet size */
- data[capas+3] = tochar(rpsiz % 95); /* ... */
- data[capas+4] = '\0';
- return(data+1); /* Return a pointer to the string */
- }
-
- /*
- * proto()--Kermit protocol entry point. Set your start state and call
- * this, NOT wart(). Modified to set long packets capability on the
- * basis of the packet size set in the external user interface.
- */
- void
- proto()
- {
- void *malloc();
- #ifdef XPRKERMIT
- struct XPR_UPDATE xpru;
-
- xpru.xpru_protocol = "XPR-Kermit";
- xpru.xpru_updatemask = XPRU_PROTOCOL;
- calla(xupdate, &xpru);
- zclear();
- #endif
- sndpkt = (char *) malloc((unsigned) (MAXSP+100));
- rcvpkt = (char *) malloc((unsigned) (MAXRP+200));
- data = (char *) malloc((unsigned) (MAXSP+4));
- if (urpsiz > 94) { /* Long packets? */
- rpsiz = (urpsiz > MAXRP - 20 ? MAXRP - 20 : urpsiz);
- lpcapr = 1; /* Request long packets */
- } else { /* No long packets */
- lpcapr = 0;
- if (urpsiz < 10) /* Too small? */
- rpsiz = 80;
- else
- rpsiz = DRPSIZ;
- }
- urpsiz = rpsiz;
- cx = cz = 0; /* Haven't aborted yet */
- if (bctr < 1)
- bctr = 1; /* Legal block check? */
- if (bctr > 3)
- bctr = 3;
- if (sndpkt == NULL || rcvpkt == NULL || data == NULL)
- #ifdef XPRKERMIT
- ST_Display_String(STMsg,"Can't allocate memory");
- #else
- tmsgl("Can't allocate memory for Kermit!!");
- #endif
- else
- wart();
- if (sndpkt) free(sndpkt);
- if (rcvpkt) free(rcvpkt);
- if (data) free(data);
- }
-
- /*
- * That ends the system-independent Kermit modules. What follows
- * are the system-dependent ones.
- */
-
- /*
- * Now for the file routines. I chose to use the z...() routines
- * written in terms of stdio.
- */
- #ifndef XPRKERMIT
- #include <stdio.h>
- #else
- typedef struct {
- int dummy;
- } FILE;
- #define EOF -1
- #endif
-
- static FILE *ifp = NULL, *ofp = NULL;
-
- #ifdef XPRKERMIT
- static
- zclear()
- {
- ifp = NULL; ofp = NULL;
- }
- #endif
-
- static
- zopeni(name) char *name; {
- #ifdef XPRKERMIT
- ifp = (FILE *) callaa(xfopen, name, "r");
- #else
- ifp = fopen(name, "r");
- #endif
- if (ifp == NULL)
- return -1;
- else
- return 0;
- }
-
- static
- zopeno(name) char *name; {
- #ifdef XPRKERMIT
- ofp = (FILE *) callaa(xfopen, name, "w");
- #else
- ofp = fopen(name, "w");
- #endif
- if (ofp == NULL)
- return -1;
- else
- return 0;
- }
-
- static
- zclosi() {
- int x;
-
- if (ifp == NULL)
- return 0;
- #ifdef XPRKERMIT
- x = calla(xfclose, ifp);
- #else
- x = fclose(ifp);
- #endif
- ifp = NULL;
- if (x < 0)
- return -1;
- else
- return 0;
- }
-
- static
- zcloso(discard) int discard; {
- int x;
-
- if (ofp == NULL)
- return 0;
- #ifdef XPRKERMIT
- x = calla(xfclose, ofp);
- #else
- x = fclose(ofp);
- #endif
- ofp = NULL;
- if (x < 0)
- return -1;
- #if 0
- else if (discard)
- if (unlink(filnam) < 0)
- return -1;
- #endif
- return 0;
- }
-
- #include <ctype.h>
-
- extern int convert; /* 0 for literal files, 1 for translate */
-
- /* name from remote to local format */
- static
- zrtol(s1,s2,warn) char *s1, *s2; int warn; {
- strcpy(s2,s1); /* for now */
- if (convert)
- while (*s2 != '\0') {
- if (isupper(*s2))
- *s2 = tolower(*s2);
- s2++;
- }
- }
-
- /* name from local to remote format */
-
- static
- zltor(s1,s2) char *s1, *s2; {
- #ifdef XPRKERMIT
- char *EndPath();
- #endif
- char dotseen = 0;
-
- if (!convert)
- strcpy(s2, s1);
- else {
- #ifdef XPRKERMIT
- s1 = EndPath(s1); /* strip dir/disk */
- #endif
- while (*s1 != '\0') {
- if (islower(*s1))
- *s2 = toupper(*s1);
- else if (isalnum(*s1))
- *s2 = *s1;
- else if (*s1 == '.')
- if (!dotseen) {
- dotseen = 1;
- *s2 = *s1;
- } else
- *s2 = 'X';
- /* else a character we're not prepared to handle. */
- s1++; s2++;
- }
- *s2 = '\0';
- }
- }
-
- /*
- * System-dependent function to return next character from file.
- * If the text flag argument is nonzero, first convert to canonic form.
- */
- static
- zgetc(text) { /* Get next char from file. */
- #define MAXREC 100 /* Size of record buffer. */
-
- static char recbuf[MAXREC + 1]; /* Big enough for MAXREC newlines */
- static char *rbp; /* Buffer pointer */
- static int i = 0; /* Buffer char counter */
- int c;
-
- if (i == 0) { /* If the buffer is empty, */
- /* read next line from file. */
- for (i = 0;
- i < MAXREC - 1 && (c = getc(ifp)) != EOF && c != '\n';
- i++)
- recbuf[i] = c;
- if (c == '\n') { /* Got newline */
- if (text) { /* If in text mode */
- recbuf[i++] = '\r'; /* Substitute CRLF */
- }
- recbuf[i++] = c;
- }
- recbuf[i] = '\0'; /* Done, terminate buffer */
- if (i == 0) return -1; /* If empty, indicate EOF */
- rbp = recbuf; /* Remember position for next time */
- }
- i--; /* Adjust the counter. */
- return(*rbp++ & 0377); /* Return hext character */
- }
-
- static
- zputc(c, text) int c, text; { /* Put character in file. */
- unsigned int x;
-
- c &= 255; /* Undo any sign extension */
- if (text && c == '\r') /* If in text mode, */
- return 0; /* eliminate carriage returns. */
- else { /* Otherwise, */
- x = putc(c, ofp) & 255; /* output the character. */
- if (c == 255) return 0; /* Special handling for all 1's */
- return ((x != c) ? -1 : 0); /* Normal return code. */
- }
- }
-
- #ifdef XPRKERMIT
- int getc(ifp)
- FILE *ifp;
- {
- unsigned char buf;
- long status;
-
- status = calladda(xfread, &buf, 1L, 1L, ifp);
- if (status == 0) return (EOF);
- else return((int) buf);
- }
-
- putc(c, ofp)
- int c;
- FILE *ofp;
- {
- int status;
- char cl;
-
- cl = c; /* useful ??? */
- status = calladda(xfwrite, &cl, 1L, 1L, ofp);
- if (status == 0) return (EOF);
- else return(c);
- }
-
- int ttol(s, n)
- char *s;
- int n;
- {
- long status;
-
- status = callad(xswrite, s, (long) n);
- if (status == 0) return(n);
- else return(-1);
- }
-
- int ttinl(s, max, eol, timeout)
- char *s;
- int max, timeout, eol;
- {
- int x = 0;
- char c;
-
- *s = '\0';
- /*
- * Willy Langeveld assures me that, since serial.device does its
- * own buffering, callling xsread once for each character isn't
- * going to take too long.
- */
- for (x = 0; x < max; x++) {
- if (calladd(xsread, &c, 1L, (long) (timeout * 1000000L)) < 0) {
- return -1;
- } else if ((s[x] = parity ? c & 127 : c) == eol) {
- break;
- } else if (xchkabort()) {
- cz = cx = brkflag = 1;
- break;
- }
- }
- s[x] = '\0';
- return(x);
- #endif
- }
-
- void ttflui()
- {
- xsflush();
- }
-
- void sleep(sec)
- int sec;
- {
- if (sec) TimeOut((long)sec);
- }
-
- #define MAXMESSAGE 50
- static char message[MAXMESSAGE+1];
- static int nmess = 0;
- static long errors = 0, blocks = 0;
-
- /* screen(f,c,n,s)
- f - argument descriptor
- c - a character or small integer
- n - a long integer
- s - a string.
- Fill in this routine with the appropriate display update for the system.
- This version for XPR Kermit.
- */
-
- screen(f,c,n,s) int f; long n; char c; char *s; {
- struct XPR_UPDATE xpru;
-
- if (!local || xflag) return;
- switch (f) {
- case SCR_PT: /* Packet Transferred. */
- if (c == 'Y') return; /* Don't bother with ACK's. */
- xpru.xpru_packettype = c;
- xpru.xpru_blocksize = strlen(s);
- xpru.xpru_blocks = ++blocks;
- xpru.xpru_bytes = ffc;
- xpru.xpru_updatemask = XPRU_PACKETTYPE | XPRU_BLOCKSIZE |
- XPRU_BLOCKS | XPRU_BYTES;
- break;
- case SCR_EM: /* Error message. */
- xpru.xpru_errormsg = s;
- xpru.xpru_updatemask = XPRU_ERRORMSG;
- break;
- default:
- return;
- }
- calla(xupdate, &xpru);
- }
-
- void tchar(c)
- char c;
- {
- struct XPR_UPDATE xpru;
-
- if (c == '%') { /* retry */
- xpru.xpru_errors = ++errors;
- xpru.xpru_updatemask = XPRU_ERRORS;
- } else if (c == '#') { /* fake it */
- xpru.xpru_errors = errors = 0;
- xpru.xpru_blocks = blocks = 0;
- nmess = 0; /* Make sure message empty. */
- xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_ERRORS;
- } else {
- message[nmess++] = c;
- if (nmess >= MAXMESSAGE)
- tflush();
- return;
- }
- calla(xupdate, &xpru);
- }
-
- static
- tflush()
- {
- struct XPR_UPDATE xpru;
-
- if (nmess <= 0)
- return;
- message[nmess] = '\0';
- xpru.xpru_errormsg = message;
- xpru.xpru_updatemask = XPRU_ERRORMSG;
- calla(xupdate, &xpru);
- nmess = 0;
- }
-
- ST_Display_String(Item, S)
- int Item;
- char *S;
- {
- struct XPR_UPDATE xpru;
-
- switch (Item) {
- case STMsg:
- xpru.xpru_msg = S;
- xpru.xpru_updatemask = XPRU_MSG; break;
- case STFile:
- xpru.xpru_filename = S;
- xpru.xpru_updatemask = XPRU_FILENAME; break;
- case STUplSize:
- xpru.xpru_filesize = callad(xfinfo, S, 1L);
- xpru.xpru_updatemask = XPRU_FILESIZE; break;
- default:
- return;
- }
- calla(xupdate, &xpru);
- }
-
- ST_Display_CRC(Item)
- int Item;
- {
- struct XPR_UPDATE xpru;
-
- switch (Item) {
- case 1:
- xpru.xpru_blockcheck = "Check-6"; break;
- case 2:
- xpru.xpru_blockcheck = "Check-12"; break;
- case 3:
- xpru.xpru_blockcheck = "CRC-16"; break;
- default:
- return;
- }
- xpru.xpru_updatemask = XPRU_BLOCKCHECK;
-
- calla(xupdate, &xpru);
- }
-
- extern char *p_pattern;
-
- #define TRUE 1
- #define FALSE 0
-
- int gnfile(fname, len)
- char *fname;
- int len; /* it is 50 */
- {
- static firsttime = TRUE;
- char buffer[256];
- static long state;
-
- if (firsttime) {
- state = callaa(xffirst, buffer, p_pattern);
- if (state) firsttime = FALSE;
- } else {
- state = calldaa(xfnext, state, buffer, p_pattern);
- if (state == 0L) firsttime = TRUE;
- }
- if (state && strlen(buffer)<len) {
- strcpy(fname, buffer);
- return((int)state);
- } else return(0);
- }
-
- char *EndPath(p)
- char *p;
- {
- char *q;
-
- q = p;
- while (*p != '\0') {
- if ((*p == '/') || (*p == ':'))
- q = p + 1;
- p++;
- }
- return(q);
- }
-