/* * Protocol module for Windows Kermit * * Copyright (c) 1990, 1991 by * William S. Hall * 3665 Benton Street #66 * Santa Clara, CA 95051 * * This module must be preprocessed by wart */ #define NOCOMM #define NOKANJI #define NOSOUND #define NOATOM #include #include #include #ifdef COLUMBIA #include "wkkerm.h" #else #include "wnkerm.h" #endif /* The state machine returns 0 to show completion or 1 if more input * is expected. Currently, these return values are not used. */ #define RESUME return(0) #define CONTINUE return(1) /* local function prototypes */ static int near input(void); static char vcmd; static int vstate; /* protocol states */ %states get rsfile rsdata ipkt rgen %states ssinit ssfile ssdata sseof sseot /* Protocol description. */ %% /* Begin file send */ s { krm_tinit(); /* initialize */ Kermit.start = 'w'; /* switch to wait */ } /* Begin get */ r { krm_tinit(); vstate = get; vcmd = 0; krm_sinit('I'); BEGIN ipkt; } /* Begin host command */ c { krm_tinit(); vstate = rgen; vcmd = 'C'; krm_sinit('I'); BEGIN ipkt; } /* Begin generic command */ g { krm_tinit(); vstate = rgen; vcmd = 'G'; krm_sinit('I'); BEGIN ipkt; } /* Wait to send first packet */ w { if (Kermit.delay) { /* timer will reset this parameter */ Kermit.start = 'w'; /* wait to send first packet */ CONTINUE; } else { if (krm_sinit('S') < 0) { /* transmit sendinit packet */ krm_err(IDS_KRM_SENDINIT_ERROR); /* error; inform remote */ RESUME; /* quit */ } krmFlushQue(); /* flush any pending input in local buffer */ BEGIN ssinit; /* prepare to open file and send file name */ } } /* Begin receive file */ v { krm_tinit(); /* initialize */ BEGIN get; } Y { krm_spar(krm_rcvpkt.data, krm_rcvpkt.len); /* read send-init data */ if (vcmd) { if (krm_sendcmd(vcmd, Kermit.pFilelist) < 0) { krm_err(IDS_KRM_SENDCMD_ERROR); /* error; inform remote */ RESUME; /* quit */ } vcmd = 0; } if (vstate == get) if (krm_srinit(Kermit.pFilelist) < 0) { krm_err(IDS_KRM_SENDR_ERROR); RESUME; } BEGIN vstate; } E { if (vcmd) if (krm_sendcmd(vcmd, Kermit.pFilelist) < 0) { krm_err(IDS_KRM_SENDCMD_ERROR); /* error; inform remote */ RESUME; /* quit */ } vcmd = 0; if (vstate == get) if (krm_srinit(Kermit.pFilelist) < 0) { krm_err(IDS_KRM_SENDR_ERROR); RESUME; } BEGIN vstate; } /* got ACK of sendinit packet */ Y { krm_spar(krm_rcvpkt.data, krm_rcvpkt.len); /* set init data */ Kermit.bctu = Kermit.bctr; /* select block check type */ Kermit.pFile = krm_getnextfile(TRUE); /* get file to send */ if (krm_sfile() < 0) { /* send file name packet */ krm_err(IDS_KRM_SENDFILENAME_ERROR); /* error; inform remote */ RESUME; /* quit */ } BEGIN ssfile; /* prepare to send first data packet */ } /* Got ACK of file name packet */ Y { int x; krm_savename(); /* post the remote's name for file */ if ((x = krm_sdata()) == 0) { /* no data in file */ if (krm_seof("") < 0) { /* send end of file */ krm_err(IDS_KRM_SENDEOF_ERROR); /* error; inform remote */ RESUME; /* quit */ } BEGIN sseof; } else if (x < 0) { /* error in sending file */ krm_rclose(FALSE); /* close the file */ krm_err(IDS_KRM_SENDDATA_ERROR); /* post error to remote and quit */ RESUME; } else BEGIN ssdata; /* prepare to receive data */ } /* Got ACK to data packet */ Y { krm_checkcnx(); /* check if transaction cancelled */ if (Kermit.abort) { if (Kermit.abort == KRM_FILEABORT) /* cancel file send */ Kermit.abort = 0; if (krm_seof("D") < 0) { /* tell remote about cancellation */ krm_err(IDS_KRM_SENDEOF_ERROR); /* error; inform remote */ RESUME; /* quit */ } BEGIN sseof; /* prepare to send end of file */ } else { int x; if ((x = krm_sdata()) == 0) { /* no more data */ if (krm_seof("") < 0) { /* send end of file */ krm_err(IDS_KRM_SENDEOF_ERROR); /* error; inform remote */ RESUME; /* quit */ } BEGIN sseof; /* prepare to send end of file */ } else if (x < 0) { /* error */ krm_rclose(FALSE); /* close the file */ krm_err(IDS_KRM_SENDDATA_ERROR); /* inform remote */ RESUME; /* quit */ } } } /* Got ACK to end of file packet */ Y { if (Kermit.pFile = krm_getnextfile(FALSE)) { /* any more files? */ if (krm_sfile() < 0) { /* send next file name */ krm_err(IDS_KRM_SENDFILENAME_ERROR); /* error, inform remote */ RESUME; /* quit */ } BEGIN ssfile; /* prepare for next file */ } else { /* no more files to send */ if (krm_seot() < 0) { /* send break */ krm_err(IDS_KRM_SENDEOT_ERROR); /* error, inform remote */ RESUME; /* quit */ } BEGIN sseot; /* prepare to exit file send */ } } /* Got ACK to end of transmission packet */ Y { krm_tend(IDS_KRM_TRANSACTION_DONE); /* clean up */ RESUME; /* quit */ } /* resend of previous I packet ACK, same sequence number */ Y { krm_srinit(Kermit.pFilelist); } Y { if (krm_rcvpkt.len > 0) krm_tend(KRM_DATA_PACKET); else krm_tend(IDS_KRM_TRANSACTION_DONE); /* clean up */ RESUME; /* quit */ } /* Got sendinit packet */ S { BYTE data[KRM_MAXDATALEN + 1]; krm_spar(krm_rcvpkt.data, krm_rcvpkt.len); /* read send-init data */ krm_ack(krm_rpar(data), data); /* return init data in ACK */ Kermit.bctu = Kermit.bctr; /* set block check type */ BEGIN rsfile; /* prepare for file name */ } /* Got file name packet */ F { if (krm_rcvfil()) { /* try to open file */ char buf[KRM_MAXDATALEN + 1]; int inlen, outlen; inlen = strlen(Kermit.pFile); /* return our name to remote */ outlen = krm_encode(buf, Kermit.pFile, sizeof(buf) - 1, &inlen); krm_ack(outlen, buf); /* send the name in ACK */ BEGIN rsdata; /* prepare to receive data */ } else { krm_err(IDS_KRM_FILE_OPEN_ERROR); /* error, inform remote */ RESUME; /* quit */ } } X { if (krm_opent()) { krm_ack(0, ""); BEGIN rsdata; } else { krm_err(IDS_KRM_TERMINAL_OPEN_ERROR); RESUME; } } /* Got data packet */ D { if (krm_rcvdata()) { switch(Kermit.abort) { /* see if abort flag is on */ case KRM_BATCHABORT: krm_ack(1, "Z"); /* cancel remaining files */ Kermit.abort = 0; break; case KRM_FILEABORT: krm_ack(1, "X"); /* cancel current file */ Kermit.abort = 0; break; default: krm_ack(0, ""); /* continue */ } } else { krm_rclose(TRUE); /* error in storing data */ krm_err(IDS_KRM_FILE_WRITE_ERROR); /* inform host */ RESUME; /* quit */ } } /* Got end of file packet */ Z { /* see if remote wants us to delete file */ if (krm_rclose(krm_rcvpkt.len && (krm_rcvpkt.data[0] == 'D') ? TRUE : FALSE)) { krm_ack(0, ""); /* acknowledge */ BEGIN rsfile; /* prepare for next file */ } else { krm_err(IDS_KRM_FILE_CLOSE_ERROR); /* error; inform remote */ RESUME; /* quit */ } } /* Got end of transmission packet */ B { krm_ack(0, ""); /* acknowledge */ krm_tend(IDS_KRM_TRANSACTION_DONE); /* clean up */ RESUME; /* quit */ } /* Packet is incomplete; return. */ $ { CONTINUE; /* continue until packet is filled */ } /* Got error packet */ E { krm_rclose(TRUE); /* close any open files */ krm_tend(KRM_DATA_PACKET); /* clean up */ RESUME; /* quit */ } /* Unrecognized packet */ . { krm_rclose(TRUE); /* close any open files */ krm_err(IDS_KRM_UNKNOWN_PACKET); /* post error to remote */ RESUME; /* quit */ } %% /* input * * provide packet type to state machine */ static int near input() { register int type; if (Kermit.start) { type = Kermit.start; Kermit.start = 0; } else { type = krm_rpack(); /* read input */ if ((type != '$') && (type != 'E')) { /* packet is complete but is not an error packet */ if ((Kermit.seq != krm_rcvpkt.seq) || strchr("NQT", type)) { /* something is wrong with packet */ if (Kermit.retries >= KermParams.RetryLimit) { /* pretend we have an error packet */ krmCreatePseudoPacket('E', PS_DONE, IDS_KRM_TOOMANYRETRIES); type = 'E'; } else if ((type == 'N') && (krm_rcvpkt.seq == ((Kermit.seq + 1) & 63))) { /* this is OK since NAK for next packet is ACK for previous */ type = 'Y'; Kermit.retries = 0; } else { /* resend previous packet and try again */ Kermit.retries += 1; Kermit.totalretries += 1; krm_resend(); type = '$'; } } else /* packet is OK; reset retry count */ Kermit.retries = 0; } } return (type); }