home *** CD-ROM | disk | FTP | other *** search
- /*
- * kermit.c: hterm kermit
- *
- * NO COPYRIGHT
- *
- * TODO:
- * receive transfer percentage
- *
- * 1.1 89/07/20 mnr ported by mnr@tkl.seiken.u-tokyo from unix kermit
- * 1.2 89/07/20 Halca.Hirano add kermit panel, time out, user interface, etc.
- * ----- V2.3.-1 distributin ----
- * 1.3 89/09/19 Halca.Hirano add user abort
- * fix incorrect transfer rate
- * ---- V2.4.0 distribution ----
- * 1.4 89/10/22 Halca.Hirano
- * add 8bit prefix feature for 7bit line users.
- * 1.5 89/10/26 Halca.Hirano
- * add long packet capability, but unusable yet.
- * 1.6 89/12/01 Halca.Hirano
- * long packet is now available.
- * 1.7 89/12/12 Halca.Hirano
- * move getnext() in file.c
- * all public functions are callable from comm. mode as well as from setup.
- * 1.8 90/01/16 Halca.Hirano
- * get rid of bugs which make devide by 0 error
- * 1.9 90/05/27 Halca.Hirano
- * BUG:
- * if pier kermit is normal kermit which is without long packet capability
- * and long packet mode
- * -> long packet request was sent
- * FIX:
- * -> request size which is requested by pier
- * 2.1 90/06/18 Halca.Hirano
- * use only one packet buffer for sending and receiving
- * 2.2 90/06/26 Halca.Hirano
- * fix receive packet size bug
- *
- * $Header: kermit.cv 1.15 90/07/04 18:01:14 hirano Exp $
- *
- */
- /*
- ** Hterm kermit file transfer module
- **
- ** This module derived from UNIX KERMIT program.
- ** Original program has next HEADER.
- ** Columbia kermit is free ware!
- **
- */
-
- /*
- * K e r m i t File Transfer Utility
- *
- * UNIX Kermit, Columbia University, 1981, 1982, 1983
- * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
- *
- * Also: Jim Guyton, Rand Corporation
- * Walter Underwood, Ford Aerospace
- *
- * usage: kermit c [lbe line baud escapechar] to connect
- * kermit s [d..iflb line baud] file ... to send files
- * kermit r [d..iflb line baud] to receive files
- *
- * where c=connect, s=send, r=receive,
- * d=debug, i=image mode, f=no filename conversion, l=tty line,
- * b=baud rate, e=escape char.
- *
- * For remote Kermit, format is either:
- * kermit r to receive files
- * or kermit s file ... to send files
- *
- */
-
- /*
- * Modification History:
- *
- * May 21 84 - Roy Smith (CUCS), strip parity from checksum in rpack()
- *
- * Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
- * - Changed MYEOL character from \n to \r.
- * - Change char to int in bufill so getc would return -1 on
- * EOF instead of 255 (-1 truncated to 8 bits)
- * - Added read() in rpack to eat the EOL character
- * - Added fflush() call in xprintMsg to force the output
- * NOTE: The last three changes are not conditionally compiled
- * since they should work equally well on any system.
- *
- * Changed Berkeley 4.x conditional compilation flag from
- * UNIX4X to UCB4X.
- * Added support for error packets and cleaned up the printing
- * routines.
- */
-
- #include "option.h"
- #ifdef KERMIT
-
- #include <stdio.h> /* Standard UNIX definitions */
- #include <setjmp.h>
- #if !defined(__TURBOC__) || __TURBOC__ >= 0x0200
- #include <sys/types.h>
- #endif
- #include <sys/stat.h>
- #include <string.h>
- #include "config.h"
- #include "hterm.h"
- #include "default.h"
- #include "global.h"
-
- /*
- * Symbol Definitions
- */
- #define MAX_LONG_PACKET_SIZE 1024 /* Maximum packet size */
- #define MAX_SHORT_PACKET_SIZE 94 /* Maximum packet size */
-
- #define MAX_TRY 10 /* Times to retry a packet */
- #define MY_QUOTE '#' /* Quote character I will use */
- #define MY_PAD 0 /* Number of padding characters I will need */
- #define MY_PAD_CHAR 0 /* Padding character I need (NULL) */
- #define MY_EOL '\r' /* End-Of-Line character I need */
- #define MY_8BIT_CHAR '&' /* 8bit prefix char */
-
- #define MY_TIME 10 /* Seconds after which I should be timed out */
- #define MAX_TIME 60 /* Maximum timeout interval */
- #define MIN_TIME 2 /* Minumum timeout interval */
-
- #define LONG_PACKET_BIT 2 /* CAPAS field long packet bit */
- #define SLIDING_WINDOW_BIT 4
- #define ATTRIBUTE_BIT 8
- #define CAPAS 10 /* capabilities field index */
-
- #define TRUE -1 /* Boolean constants */
- #define FALSE 0
-
- /* Macro Definitions */
- /*
- * tochar: converts a control character to a printable one by adding a space.
- *
- * unchar: undoes tochar.
- *
- * ctl: converts between control characters and printable characters by
- * toggling the control bit (ie. ^A becomes A and A becomes ^A).
- */
- #define tochar(ch) ((ch) + ' ')
- #define unchar(ch) ((ch) - ' ')
- #define ctl(ch) ((ch) ^ 64 )
-
- /* Global Variables */
- static int recflg = 0; /* Now receiving, activate timer */
-
- static int size; /* Size of present data */
- static int rpsiz; /* Maximum receive packet size */
- static int spsiz; /* Maximum send packet size */
- static int pad; /* How much padding to send */
- static int timint; /* Timeout for foreign host on sends */
- static int n; /* Packet number */
- static int numtry; /* Times this packet retried */
- static int oldtry; /* Times previous packet retried */
- static int slen; /* sent bytes */
- static long sendnum; /* internal counter for print stat */
- static long recnum; /* internal counter for print stat */
- static int rlen; /* received bytes */
- static int totalRetry; /* total retry counter thru transferring */
- static int rateTimer; /* a counter for transfer rate measurment */
- static long bytes; /* bytes transferred */
- static long lastBytes; /* bytes transferred for rate */
- static long bytesToSend; /* bytes to send for percentage */
- static int bit8Prefix; /* bit8 prefix char */
- static int bit8PrefixUsed; /* bit8 prefix is used */
- static int bit8PrefixRequested; /* bit8 prefix requested flag */
- static int sentBit8Prefix; /* bit8 prefix my request */
-
- static char state; /* Present state of the automaton */
- static char padchar; /* Padding character to send */
- static char eol; /* End-Of-Line character to send */
- static char quote; /* Quote character in incoming data */
- static char *fileList; /* List of files to be sent */
- static char *filnam; /* Current file name */
- static char *packet = XFerBuffer; /* Packet buffer */
-
- static FILE *fp; /* File pointer for current disk file */
- static jmp_buf env; /* Environment ptr for timeout longjump */
- static char localFile[MAX_FILE_NAME] = DEFAULT_KERMIT_FILENAME;
- static int oldMode; /* caller's mode */
-
- static long LZERO = 0L;
- /*
- * prototypes
- */
- int sendsw(void);
- char sinit(void);
- char sfile(void);
- char sdata(void);
- char seof(void);
- char sbreak(void);
- int recsw(void);
- char rinit(void);
- char rfile(void);
- char rdata(void);
- int finishsw(void);
- char dofinish(void);
- int doget(void);
- void tellAbort(void);
- void clkint(int v);
- int updateRetry(void);
- void spack(char, int, int, char *);
- int rpack(int *, int *, char *);
- int bufill(char []);
- int bufemp(char [], int);
- void spar(char []);
- void rpar(char [], int);
- void msgAbort(void);
- void kread(char *, int);
- void kwrite(char *, int);
- #define alarm(n) (kermitTimer = n * TICK_SEC)
- #define kwrite(buf,len) rowOutPortBuffer(buf, len)
-
- int kbegin(msg)
- char *msg;
- {
- oldMode = mode;
- mode = M_SETUP;
- if (oldMode == M_COMM)
- showPage1();
-
- if (*msg && (emacs(msg, localFile, MAX_FILE_NAME, (E_HELP|E_FILE)) == ERR
- || localFile[0] == '\0')) {
- if (oldMode == M_COMM)
- showPage0();
- mode = oldMode;
- return(NO);
- }
- /*
- * Initialize these values and hope the first packet will get across OK
- */
- eol = CR; /* EOL for outgoing packets */
- quote = '#'; /* Standard control-quote char "#" */
- pad = 0; /* No padding */
- padchar = NULL; /* Use null if any padding wanted */
- rpsiz = xmodemLongP ? MAX_LONG_PACKET_SIZE : MAX_SHORT_PACKET_SIZE;
- spsiz = xmodemLongP ? MAX_LONG_PACKET_SIZE : MAX_SHORT_PACKET_SIZE;
- bit8Prefix = MY_8BIT_CHAR; /* bit8 prefix char */
- bit8PrefixUsed = NO; /* bit8 prefix is not used */
- bit8PrefixRequested = -1; /* request unknown */
- sentBit8Prefix = 'Y'; /* bit8 prefix my request */
-
- bytes = 0;
- sendnum = LZERO; /* internal counter for print stat */
- recnum = LZERO;
- totalRetry = 0;
-
- /*
- * initial screen
- */
- xferPanel("kermit");
- xprintMsg(X_PROTOCOL, "kermit", LZERO);
- showHelp = 1;
- downLoading = YES;
- return(YES);
- }
-
- void kend(msg, status)
- char *msg;
- int status;
- {
- downLoading = NO;
- if (fp)
- fclose(fp);
- bell();
-
- if (oldMode == M_COMM) {
- showPage0();
- putComment(msg, (status == FALSE) ? " failed" : " done");
- }
- mode = oldMode;
- }
-
- void krec()
- {
- int status;
-
- if (kbegin("") == NO) /*Initialize variable */
- return;
- xprintMsg(X_STATUS, "Receive", LZERO);
- if ((status = recsw()) == FALSE) /* Receive the file(s) */
- xprintMsg(X_STATUS, "Receive failed", LZERO);
- else /* Report failure */
- xprintMsg(X_STATUS, "Receive done", LZERO);
- kend("rec", status);
- }
-
- void ksend()
- {
- int status;
-
- if (kbegin("Kermit send files: ") == NO) /* Initialize variable */
- return;
- fp = NULL; /* Indicate no file open yet */
-
- fileList = localFile;
- status = FALSE;
- if (getNextFileName(1, &fileList, &filnam, NO) != NO) { /* set first file name */
- xprintMsg(X_STATUS, "Send", LZERO);
- if ((status = sendsw()) == FALSE) /* Send the file(s) */
- xprintMsg(X_STATUS, "Send failed", LZERO);
- else /* or */
- xprintMsg(X_STATUS, "Send done", LZERO);
- } else {
- sprintf(packet, "%s not found", localFile);
- xprintMsg(X_ERROR, packet, LZERO);
- bell();
- }
- kend("send", status);
- }
-
- /*
- ** Issue 'finish' packette
- */
- void kfinish()
- {
- int status;
-
- kbegin("");
- xprintMsg(X_STATUS, "Finish remote server", LZERO);
- if ((status = finishsw()) == FALSE)
- xprintMsg(X_STATUS, "Finish failed", LZERO);
- else
- xprintMsg(X_STATUS, "Finish done", LZERO);
- kend("finish", status);
- }
-
- void kget()
- {
- int status;
-
- if (kbegin("Kermit remote file: ") == NO) /* Initialize variable */
- return;
- fp = NULL; /* Indicate no file open yet */
- filnam = localFile;
-
- xprintMsg(X_STATUS, "Get", LZERO);
- if ((status = doget()) == FALSE) /* Send the file(s) */
- xprintMsg(X_STATUS, "Get failed", LZERO);
- else /* or */
- xprintMsg(X_STATUS, "Get Done", LZERO);
- kend("get", status);
- }
-
- /*
- ** sendsw()
- *
- * Sendsw is the state table switcher for sending files. It loops until
- * either it finishes, or an error is encountered. The routines called
- * by sendsw are responsible for changing the state.
- *
- */
- static int sendsw()
- {
- state = 'S'; /* Send initiate is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- totalRetry = 0;
- while(TRUE) { /* Do this as long as necessary */
- switch(state) {
- case 'S': state = sinit(); break; /* Send-Init */
- case 'F': state = sfile(); break; /* Send-File */
- case 'D': state = sdata(); break; /* Send-Data */
- case 'Z': state = seof(); break; /* Send-End-of-File */
- case 'B': state = sbreak(); break; /* Send-Break */
- case 'C': return (TRUE); /* Complete */
- case 'A': return (FALSE); /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
- /*
- ** sinit()
- *
- * Send Initiate: send this host's parameters and get other side's back.
- */
- static char sinit()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A');
- spar(packet); /* Fill up init info packet */
-
- flushInputBuffer(); /* Flush pending input */
-
- spack('S', n, strlen(packet), packet); /* Send an S packet */
- switch(rpack(&len, &num, packet)) { /* What was the reply? */
- case 'N':
- return(state); /* NAK, try it again */
- case 'Y': /* ACK */
- if (n != num) /* If wrong ACK, stay in S state */
- return(state); /* and try again */
- rpar(packet, len); /* Get other side's init info */
-
- if (eol == 0)
- eol = '\n'; /* Check and set defaults */
- if (quote == 0)
- quote = '#';
-
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- xprintMsg(X_PSIZE, NULL, (long)spsiz);
- return('F'); /* OK, switch state to F */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, try again */
- case 'Q': /* aborted by user */
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Anything else, just "abort" */
- }
- }
-
- /*
- ** sfile()
- *
- * Send File Header.
- */
- static char sfile()
- {
- int num, len; /* Packet number, length */
- char *cp; /* char pointer */
- struct stat fileStat;
-
- if (updateRetry())
- return('A');
-
- if (fp == NULL) { /* If not already open, */
- xprintMsg(X_FILENAME, filnam, LZERO);
- if ((fp = fopen(filnam,"rb")) == NULL) {
- sprintf(packet, "'%s' open failed", filnam);
- xprintMsg(X_ERROR, packet, LZERO);
- return('A');
- }
- }
-
- cp = strrchr(filnam, '/');
- if (cp)
- cp++;
- else
- cp = filnam;
-
- fstat(fileno(fp), &fileStat);
- bytesToSend = fileStat.st_size; /* set file size to send */
- xprintMsg(X_PERCENT, NULL, LZERO);
- rateTimer = 4; /* sample per 4 packets */
- timerValue = 30000;
- lastBytes = 0;
-
- xprintMsg(X_FILENAME, cp, LZERO); /* display file name */
- spack('F',n,strlen(cp),cp); /* Send an F packet */
- switch(rpack(&len,&num,packet)) { /* What was the reply? */
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
- case 'Y': /* ACK */
- if (n != num)
- return(state); /* If wrong ACK, stay in F state */
- numtry = 0; /* Reset try counter */
- bytes = 0;
- xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
- xprintMsg(X_STATUS, "Sending", LZERO);
- n = (n+1)%64; /* Bump packet count */
- size = bufill(packet); /* Get first data from file */
- return('D'); /* Switch state to D */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO);/* print error msg */
- fclose(fp);
- fp = NULL;
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, stay in F state */
- case 'Q': /* aborted by user */
- fclose(fp);
- fp = NULL;
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Something else, just "abort" */
- }
- }
-
-
- /*
- ** sdata
- *
- * Send File Data
- */
- static char sdata()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A'); /* If too many tries, give up */
-
- spack('D',n,size,packet); /* Send a D packet */
- switch(rpack(&len,&num, packet)) { /* What was the reply? */
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
- case 'Y': /* ACK */
- if (n != num)
- return(state); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- bytes += slen;
- lastBytes += slen;
- xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
- if (bytesToSend)
- xprintMsg(X_PERCENT, NULL, (long)((bytes*100)/bytesToSend));
- if (--rateTimer < 0) {
- xprintMsg(X_RATE, NULL, (long)((lastBytes*1000L)/(long)((long)(30000-timerValue)*TICK_INTERVAL)));
- timerValue = 30000;
- rateTimer = 4;
- lastBytes = 0;
- }
- n = (n+1)%64; /* Bump packet count */
- if ((size = bufill(packet)) == EOF) /* Get data from file */
- return('Z'); /* If EOF set state to that */
- return('D'); /* Got data, stay in state D */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- fclose(fp);
- fp = NULL;
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, stay in D */
- case 'Q': /* aborted by user */
- fclose(fp);
- fp = NULL;
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Anything else, "abort" */
- }
- }
-
- /*
- ** seof()
- *
- * Send End-Of-File.
- */
- static char seof()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A'); /* If too many tries, "abort" */
-
- spack('Z',n,0,packet); /* Send a 'Z' packet */
- switch(rpack(&len,&num,packet)) { /* What was the reply? */
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
- case 'Y': /* ACK */
- if (n != num)
- return(state); /* If wrong ACK, hold out */
- numtry = 0; /* Reset try counter */
- bytes += slen;
- xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
- if (bytesToSend)
- xprintMsg(X_PERCENT, NULL, (long)((bytes*100)/bytesToSend));
- n = (n+1)%64; /* and bump packet count */
- fclose(fp); /* Close the input file */
- fp = NULL; /* Set flag indicating no file open */
- if (getNextFileName(0, &fileList, &filnam, NO) == NO) /* No more files go? */
- return('B'); /* if not, break, EOT, all done */
- return('F'); /* More files, switch state to F */
- case 'E': /* Error packet received */
- fclose(fp);
- fp = NULL;
- xprintMsg(X_ERROR, packet, LZERO);/* print error msg */
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, stay in Z */
- case 'Q': /* aborted by user */
- fclose(fp);
- fp = NULL;
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Something else, "abort" */
- }
- }
-
- /*
- ** sbreak()
- *
- * Send Break (EOT)
- */
-
- static char sbreak()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A'); /* If too many tries "abort" */
-
- spack('B',n,0,packet); /* Send a B packet */
- switch (rpack(&len,&num,packet)) { /* What was the reply? */
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless NAK for previous packet, */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
- case 'Y': /* ACK */
- if (n != num)
- return(state); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* and bump packet count */
- return('C'); /* Switch state to Complete */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO);/* print error msg */
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, stay in B */
- case 'Q': /* aborted by user */
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return ('A'); /* Other, "abort" */
- }
- }
-
- /*
- ** recsw()
- *
- * This is the state table switcher for receiving files.
- */
-
- static int recsw()
- {
- char rinit(), rfile(), rdata(); /* Use these procedures */
-
- state = 'R'; /* Receive-Init is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- totalRetry = 0;
-
- while(TRUE) {
- switch(state) { /* Do until done */
- case 'R': state = rinit(); break; /* Receive-Init */
- case 'F': state = rfile(); break; /* Receive-File */
- case 'D': state = rdata(); break; /* Receive-Data */
- case 'C': return(TRUE); /* Complete state */
- case 'A': return(FALSE); /* "Abort" state */
- }
- }
- }
-
-
- /*
- ** rinit()
- *
- * Receive Initialization
- */
- static char rinit()
- {
- int len, num; /* Packet length, number */
-
- if (updateRetry())
- return('A'); /* If too many tries, "abort" */
-
- switch(rpack(&len,&num,packet)) { /* Get a packet */
- case 'S': /* Send-Init */
- rpar(packet, len); /* Get the other side's init data */
- spar(packet); /* Fill up packet with my init info */
- spack('Y',n,strlen(packet),packet); /* ACK with my parameters */
- xprintMsg(X_PSIZE, NULL, (long)rpsiz);
- oldtry = numtry; /* Save old try count */
- numtry = 0; /* Start a new counter */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('F'); /* Enter File-Receive state */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- return('A'); /* abort */
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
- case 'Q': /* aborted by user */
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Some other packet type, "abort" */
- }
- }
-
-
- /*
- ** rfile()
- *
- * Receive File Header
- */
- static char rfile()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A'); /* "abort" if too many tries */
-
- switch(rpack(&len,&num,packet)) {/* Get a packet */
- case 'S': /* Send-Init, maybe our ACK lost */
- if (oldtry++ > MAX_TRY)
- return('A'); /* If too many tries "abort" */
- if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */
- /* Yes, ACK it again with */
- spar(packet); /* our Send-Init parameters */
- spack('Y',num,strlen(packet),packet);
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in this state */
- } else
- return('A'); /* Not previous packet, "abort" */
- case 'Z': /* End-Of-File */
- if (oldtry++ > MAX_TRY)
- return('A');
- if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */
- /* Yes, ACK it again. */
- spack('Y',num,0,0);
- numtry = 0;
- return(state); /* Stay in this state */
- } else
- return('A'); /* Not previous packet, "abort" */
- case 'F': /* File Header (just what we want) */
- if (num != n)
- return('A'); /* The packet number must be right */
- xprintMsg(X_FILENAME, packet, LZERO);
- if ((fp=fopen(packet,"wb"))==NULL) { /* Try to open a new file */
- xprintMsg(X_ERROR, "File create failed", LZERO);
- /* send E packet to remote host? */
- return('A');
- } else /* OK, give message */
- xprintMsg(X_STATUS, "Receiving", LZERO);
-
- xprintMsg(X_PERCENT, "", -1L);
-
- spack('Y',n,0,0); /* Acknowledge the file header */
- oldtry = numtry; /* Reset try counters */
- numtry = 0; /* ... */
- bytes = 0; /* iniz number of transfer bytes*/
- xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
- rateTimer = 4; /* sample per 4 packets */
- timerValue = 30000;
- lastBytes = 0;
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Switch to Data state */
- case 'B': /* Break transmission (EOT) */
- if (num != n)
- return ('A'); /* Need right packet number here */
- spack('Y',n,0,0); /* Say OK */
- return('C'); /* Go to complete state */
- case 'E': /* Error packet received */
- if (fp)
- fclose(fp);
- fp = NULL;
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- return('A'); /* abort */
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
- case 'Q': /* aborted by user */
- if (fp)
- fclose(fp);
- fp = NULL;
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return ('A'); /* Some other packet, "abort" */
- }
- }
-
-
- /*
- ** rdata()
- *
- * Receive Data
- */
- static char rdata()
- {
- int num, len; /* Packet number, length */
-
- if (updateRetry())
- return('A'); /* "abort" if too many tries */
-
- switch(rpack(&len,&num,packet)) { /* Get packet */
- case 'D': /* Got Data packet */
- xprintMsg(X_PSIZE, NULL, (long)len);
- if (num != n) { /* if Not Right packet */
- if (oldtry++ > MAX_TRY)
- return('A'); /* If too many tries, abort */
- if (num == ((n==0) ? 63:n-1)) { /* Else check packet number */
- /* Previous packet again? */
- spack('Y',num,6,packet); /* Yes, re-ACK it */
- numtry = 0; /* Reset try counter */
- return(state); /* Don't write out data! */
- } else
- return('A'); /* sorry, wrong number */
- }
- /* Got data with right packet number */
- if (bufemp(packet,len)) { /* Write the data to the file */
- xprintMsg(X_ERROR, "File write error", LZERO);
- tellAbort();
- return('A');
- }
- bytes += rlen;
- lastBytes += rlen;
- xprintMsg(X_KBYTES, NULL, (long)(bytes/1024));
- if (--rateTimer < 0) {
- xprintMsg(X_RATE, NULL, (long)((lastBytes*1000L)/(long)((long)(30000-timerValue)*TICK_INTERVAL)));
- timerValue = 30000;
- rateTimer = 4;
- lastBytes = 0;
- }
- spack('Y',n,0,0); /* Acknowledge the packet */
- oldtry = numtry; /* Reset the try counters */
- numtry = 0; /* ... */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Remain in data state */
- case 'F': /* Got a File Header */
- if (oldtry++ > MAX_TRY)
- return('A'); /* If too many tries, "abort" */
- if (num == ((n==0) ? 63:n-1)) { /* Else check packet number */
- /* It was the previous one */
- spack('Y',num,0,0); /* ACK it again */
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in Data state */
- } else
- return('A'); /* Not previous packet, "abort" */
- case 'Z': /* End-Of-File */
- if (num != n)
- return('A'); /* Must have right packet number */
- spack('Y',n,0,0); /* OK, ACK it. */
- numtry = 0;
- fclose(fp); /* Close the file */
- fp = NULL;
- xprintMsg(X_PERCENT, "", 100L);
- n = (n+1)%64; /* Bump packet number */
- return('F'); /* Go back to Receive File state */
- case 'E': /* Error packet received */
- if (fp)
- fclose(fp);
- fp = NULL;
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- return('A'); /* abort */
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
- case 'Q': /* aborted by user */
- if (fp)
- fclose(fp);
- fp = NULL;
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Some other packet, "abort" */
- }
- }
-
-
- static int finishsw()
- {
- char cinit(), dofinish();
-
- state = 'F'; /* Send initiate is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- while(TRUE) { /* Do this as long as necessary */
- switch(state) {
- case 'F': state = dofinish(); break; /* Do-finish */
- case 'Y': return (TRUE); /* Complete */
- case 'A': return (FALSE); /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
- static char dofinish()
- {
- int num, len; /* Packet number, length */
- char finishCmd = 'F';
-
- if (updateRetry())
- return('A'); /* If too many tries, give up */
-
-
- flushInputBuffer(); /* Flush pending input */
-
- spack('G',n,2, &finishCmd); /* Send an S packet */
- switch(rpack(&len,&num,packet)) { /* What was the reply? */
- case 'N':
- return(state); /* NAK, try it again */
- case 'Y': /* ACK */
- if (n != num) /* If wrong ACK, stay in S state */
- return(state); /* and try again */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- return('Y'); /* OK, switch state to F */
- case 'E': /* Error packet received */
- xprintMsg(X_ERROR, packet, LZERO); /* print error msg */
- return('A'); /* abort */
- case FALSE:
- return(state); /* Receive failure, try again */
- case 'Q': /* aborted by user */
- msgAbort();
- tellAbort(); /* send 'E' packet */
- return('A');
- default:
- return('A'); /* Anything else, just "abort" */
- }
- }
-
- /*
- ** doget()
- *
- * Issue 'R' packet and then do recsw
- */
-
- static int doget()
- {
- flushInputBuffer(); /* Flush pending input */
- spack('R',n,strlen(filnam),filnam); /* Send an R packet */
- return (recsw());
- }
-
- /*
- * KERMIT utilities.
- */
-
- static void tellAbort()
- {
- char *msg = "Aborted by user";
-
- spack('E', n, strlen(msg), msg);
- }
-
- static void clkint(v) /* Timer interrupt handler */
- int v;
- {
- longjmp(env,v); /* Tell rpack to give up */
- }
-
- static int updateRetry()
- {
- if (numtry++ > MAX_TRY)
- return(1); /* If too many tries, give up */
- if (numtry > 1)
- totalRetry++;
- xprintMsg(X_RETRY, NULL, (long)totalRetry);
- return(0);
- }
-
- /*
- ** spack()
- *
- * Send a Packet
- */
- static void spack(type,num,len,data)
- char type;
- int num;
- int len;
- char *data;
- {
- int i, len2; /* Character loop counter */
- register char chksum, chksum2; /* Checksum, packet buffer */
- char *lenp;
- register char *bufp; /* Buffer pointer */
- char sendpkt[20]; /* header buffer */
-
- /*
- * send padding chars
- */
- for (i=1; i<=pad; i++) {
- kwrite(&padchar, 1); /* Issue any padding */
- }
-
- /*
- * build a header part and send it
- */
- bufp = sendpkt; /* Set up buffer pointer */
- chksum = 0;
- *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */
- lenp = bufp++;
- *bufp++ = tochar(num); /* Packet number */
- chksum += tochar(num); /* Update checksum */
- *bufp++ = type; /* Packet type */
- chksum += type; /* Update checksum */
- len2 = len + 1; /* len + checksum len */
- if (len2 > 95) { /* if long packet */
- *lenp++ = tochar(0); /* zero length */
- chksum += tochar(0);
- *bufp++ = tochar(len2 / 95); /* high part */
- chksum += tochar(len2 / 95);
- *bufp++ = tochar(len2 % 95); /* low part */
- chksum += tochar(len2 % 95);
- chksum2 = (((chksum&0300)>>6)+chksum) & 077;
- *bufp++ = tochar(chksum2);
- chksum += tochar(chksum2);
- } else {
- *lenp = tochar(len2+2); /* Send the character count */
- chksum += tochar(len2+2); /* Initialize the checksum */
- }
- kwrite(sendpkt, bufp-sendpkt); /* send header */
-
- /*
- * calc check sum for the the data part then send the data part
- */
- for (i=0, bufp = data; i<len; i++)
- chksum += *bufp++; /* Update checksum */
- kwrite(data, len); /* send data */
-
- /*
- * build trailer part then send it
- */
- bufp = sendpkt; /* prepare trailer buffer */
- chksum = (((chksum&0300)>>6)+chksum)&077; /* Compute final checksum */
- *bufp++ = tochar(chksum); /* Put it in the packet */
- *bufp = eol; /* Extra-packet line terminator */
- kwrite(sendpkt,bufp-sendpkt+1); /* Send the packet */
- xprintMsg(X_PSENT, NULL, (long)(sendnum++)); /* print sent packet num */
- }
-
- /*
- ** rpack()
- *
- * Read a Packet
- */
- static int rpack(len,num,data)
- int *len;
- int *num; /* Packet length, number */
- char *data; /* Packet data */
- {
- int c;
- int i, done; /* Data character number, loop exit */
- int len2;
- char t, /* Current input character */
- type, /* Packet type */
- cchksum, /* Our (computed) checksum */
- rchksum; /* Checksum received from other host */
-
- if ((c = setjmp(env)) == TRUE)
- return FALSE; /* Timed out, fail */
- else if (c == 'Q')
- return('Q'); /* aborted by user */
- recflg = 1;
-
- if ((timint > MAX_TIME) || (timint < MIN_TIME))
- timint = MY_TIME;
- alarm(timint);
-
- do {
- kread(&t,1);
- t &= 0177; /* Handle parity */
- } while (t != SOH); /* Wait for packet header */
-
- done = FALSE; /* Got SOH, init loop */
- while (!done) { /* Loop to get a packet */
- kread(&t,1); /* Get character */
- if (t == SOH)
- continue; /* Resynchronize if SOH */
- cchksum = t; /* Start the checksum */
- len2 = unchar(t); /* len2 = 0 if long packet */
- if (len2)
- *len = len2 - 3; /* data count */
-
- kread(&t,1); /* Get character */
- if (t == SOH)
- continue; /* Resynchronize if SOH */
- cchksum = cchksum + t; /* Update checksum */
- *num = unchar(t); /* Packet number */
-
- kread(&t,1); /* Get character */
- if (t == SOH)
- continue; /* Resynchronize if SOH */
- cchksum = cchksum + t; /* Update checksum */
- type = t; /* Packet type */
-
- if (len2 == 0) { /* long packet */
- kread(&t, 1);
- cchksum += t;
- *len = unchar(t) * 95;
- kread(&t, 1);
- cchksum += t;
- *len += unchar(t);
- kread(&t, 1); /* header check sum (ignored) */
- cchksum += t;
- *len -= 1; /* to real data */
- }
-
- for (i = 0; i < *len; i++) { /* The data itself, if any */
- kread(&t,1); /* Get character */
- if (t == SOH)
- continue; /* Resynch if SOH */
- cchksum = cchksum + t; /* Update checksum */
- data[i] = t; /* Put it in the data buffer */
- }
- data[*len] = 0; /* Mark the end of the data */
-
- kread(&t,1); /* Get last character (checksum) */
- rchksum = unchar(t); /* Convert to numeric */
- kread(&t,1); /* get EOL character and toss it */
- if (t == SOH)
- continue; /* Resynchronize if SOH */
- done = TRUE; /* Got checksum, done */
- }
-
- recflg = 0;
- /* Fold in bits 7,8 to compute */
- cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
-
- if (cchksum != rchksum) {
- return(FALSE);
- }
-
- xprintMsg(X_PRECV, NULL, (long)(recnum++)); /* print received packet num */
-
- return(type); /* All OK, return packet type */
- }
-
-
- /*
- ** bufill()
- *
- * Get a bufferful of data from the file that's being sent.
- * Only control-quoting is done; 8-bit & repeat count prefixes are
- * not handled.
- */
-
- static bufill(buffer)
- char buffer[]; /* Buffer */
- {
- int i, /* Loop index */
- t; /* Char read from file */
- u_char t7; /* 7-bit version of above */
-
- i = 0; /* Init data buffer pointer */
- slen = 0;
- while((t = getc(fp)) != EOF) { /* Get the next character */
- slen++; /* inc send file length */
- t7 = t & 0x7f; /* Get low order 7 bits */
-
- if (bit8PrefixUsed && (t & 0x80)) {
- buffer[i++] = bit8Prefix;
- t = t7;
- }
- if (t7 < SPACE || t7 == DEL) { /* Does this char require */
- buffer[i++] = quote; /* Quote the character */
- t = ctl(t);
- }
- if (t7 == quote)
- buffer[i++] = quote;
- if (bit8PrefixUsed && (t7 == bit8Prefix))
- buffer[i++] = quote;
-
- buffer[i++] = t; /* Deposit the character itself */
- buffer[i] = '\0';
- if (i >= spsiz-11) /* 8 */
- return(i); /* Check length */
- }
- if (i==0)
- return(EOF); /* Wind up here only on EOF */
- return(i); /* Handle partial buffer */
- }
-
-
- /*
- ** bufemp()
- *
- * Put data from an incoming packet into a file.
- */
- static bufemp(buffer,len)
- char buffer[]; /* Buffer */
- int len; /* Length */
- {
- int i; /* Counter */
- char t; /* Character holder */
- u_char b8, a7;
-
- rlen = 0;
- for (i=0; i<len; i++) { /* Loop thru the data field */
- t = buffer[i]; /* Get character */
- b8 = 0;
- if (bit8PrefixUsed) {
- if (t == bit8Prefix) {
- b8 = 0x80;
- t = buffer[++i];
- }
- }
- if (t == quote) { /* Control quote */
- t = buffer[++i]; /* Get the quoted character */
- a7 = (t & 0x7f);
- if ((a7 >= 0100 && a7 <= 0137) || a7 == '?')
- t = ctl(t); /* No, uncontrollify it */
- }
- t |= b8;
- if (putc(t, fp) == EOF) {
- return(ERR);
- }
- rlen++;
- }
- return(OK);
- }
-
-
- /*
- ** spar()
- *
- * Fill the data array with my send-init parameters
- *
- */
- static void spar(data)
- char data[];
- {
- /*
- * Biggest packet I can receive
- * send short one first, send long one later in capabilities
- * short one may be used by dumb-kermit and long one may be used
- * by c-kermit.
- */
- data[0] = tochar(MAX_SHORT_PACKET_SIZE);
-
- /*
- * other parameters
- */
- data[1] = tochar(MY_TIME); /* When I want to be timed out */
- data[2] = tochar(MY_PAD); /* How much padding I need */
- data[3] = ctl(MY_PAD_CHAR); /* Padding character I want */
- data[4] = tochar(MY_EOL); /* End-Of-Line character I want */
- data[5] = MY_QUOTE; /* Control-Quote character I send */
- switch (bit8PrefixRequested) {
- case -1: /* unknown */
- case 1: /* 'Y' is requested */
- switch (paritybit) {
- case NO_PAR_8:
- case EV_PAR_8: break;
- case NO_PAR_7:
- case EV_PAR_7:
- case SP_PAR_7:
- sentBit8Prefix = bit8Prefix = MY_8BIT_CHAR;
- break;
- }
- break;
- case 0: /* 'N' is requested */
- case 2: /* prefix char is requested */
- break;
- }
- data[6] = sentBit8Prefix;
- data[7] = 1 + '0'; /* one char check sum */
- data[8] = ' '; /* No repeat prefix */
- data[9] = '\0';
-
- if (xmodemLongP) {
- data[9] = tochar(LONG_PACKET_BIT); /* CAPAS field */
- data[CAPAS] = tochar(0); /* No window sliding */
- data[CAPAS+1] = tochar(rpsiz / 95);
- data[CAPAS+2] = tochar(rpsiz % 95); /* long packet size */
- data[CAPAS+3] = '\0';
- }
- }
-
-
- /*
- ** rpar()
- *
- * Get the other host's send-init parameters
- *
- */
-
- static void rpar(data, len)
- char data[];
- int len; /* packet length */
- {
- int rq, x, capas;
-
- x = unchar(data[0]); /* Maximum packet size other kermit can receive */
- if (x < spsiz) {
- spsiz = x;
- if (spsiz < 10 || (xmodemLongP == NO))
- spsiz = 80;
- }
- timint = unchar(data[1]); /* When I should time out */
- pad = unchar(data[2]); /* Number of pads to send */
- padchar = ctl(data[3]); /* Padding character to send */
- eol = unchar(data[4]); /* EOL character I must send */
- quote = data[5]; /* Incoming data quote character */
- /*
- * bit 8 prefix
- */
- rq = (len >= 7) ? data[6] : 0;
- if (rq == 'Y') {
- bit8PrefixRequested = 1;
- switch (paritybit) {
- case NO_PAR_8:
- case EV_PAR_8: break;
- case NO_PAR_7:
- case EV_PAR_7:
- case SP_PAR_7:
- bit8PrefixUsed = YES;
- bit8Prefix = '&';
- break;
- }
- }else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) {
- bit8PrefixRequested = 2;
- bit8PrefixUsed = (bit8Prefix == sentBit8Prefix || sentBit8Prefix == 'Y');
- if (bit8PrefixUsed)
- bit8Prefix = rq;
- } else {
- bit8PrefixRequested = 0;
- bit8PrefixUsed = NO;
- }
- /*
- * block check
- */
- if (len >= 8)
- ;
- /*
- * repeat prefix
- */
- if (len >= 9)
- ;
- /*
- * capabilities
- */
- if (len >= 10) {
- x = unchar(data[9]);
- for (capas = 10; (unchar(data[capas-1]) & 1) && (len >= capas); capas++)
- ; /* skip other CAPAS field */
- }
- /*
- * Maximum packet size other kermit can receive (long packet)
- */
- if ((x & LONG_PACKET_BIT) && len > capas+2) {
- x = unchar(data[capas+1]) * 95 + unchar(data[capas+2]);
- if (xmodemLongP) /* long packet is requested by user */
- spsiz = (x > MAX_LONG_PACKET_SIZE) ? MAX_LONG_PACKET_SIZE : x;
- else
- spsiz = (x > MAX_SHORT_PACKET_SIZE) ? MAX_SHORT_PACKET_SIZE : x;
- if (spsiz < 10)
- spsiz = 80;
- }
- }
-
-
- static void msgAbort()
- {
- xprintMsg(X_ERROR, "Aborted by user", LZERO);
- }
-
- /*
- * basic I/O
- */
- static void kread(buf, len)
- char *buf;
- int len;
- {
- register int c;
- register int bp;
-
- for (bp = 0; bp < len; ) {
- if ((c = getSerial()) != -1) {
- buf[bp] = c & cMask;
- bp++;
- } else {
- if ((c = keyin()) != -1)
- if (c == 0x1b) /* ESC */
- clkint('Q');
- }
- if (kermitTimer <= 0)
- clkint(TRUE); /* time out */
- }
- }
- #endif /* KERMIT */
-