char *protv = "C-Kermit Protocol Module 4C(026), 12 Jun 85"; /* -*-C-*- */ /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Modified for sliding windows impl. by: Jan A. van der Eijk */ #include "lckdeb.h" #include "lckerm.h" /* Note -- This file may also be preprocessed by the Unix Lex program, but you must indent the above #include statement before using Lex, and then restore it to the left margin in the resulting C program before compilation. Also, the invocation of the "wart()" function below must be replaced by an invocation of the "yylex()" function. It might also be necessary to remove comments in the %%...%% section. */ /* State definitions for Wart (or Lex) */ %states rfile rdata ssinit ssdata sseof sseot get rattr ssattr swdata rwdata swe /* External C-Kermit variable declarations */ extern char sstate, *versio, *cmarg, *cmarg2; extern char data[], filnam[], ttname[]; extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp; extern int prvpkt, cxseen, czseen, local, displa, bctu, bctr, quiet; extern int putfil(), errpkt(); extern int filatr,nxtcas, rpktno, window; /* Local variables */ static char vstate = 0; /* Saved State */ static char vcmd = 0; /* Saved Command */ static int x; /* General-purpose integer */ /* Macros - Note, BEGIN is predefined by Wart (and Lex) */ #define RESUME return %% /* Protocol entry points, one for each start state (sstate) */ s { tinit(); /* Do Send command */ if (sinit()) BEGIN ssinit; else RESUME; } v { tinit(); sleep(1); nack(); BEGIN get; } /* Receive */ a { errpkt("User cancelled transaction"); /* Tell other side what's going on */ clsif(); clsof(); return(0); } /* Return from protocol. */ /* Dynamic states: input-character { action } */ S { rinit(data); bctu = bctr; BEGIN rfile; } /* Send-Init */ F { if (rcvfil()) { /* A file is coming */ ack(); if (filatr) BEGIN rattr; /* Both want attributes */ else if ( wdinit() ) BEGIN rwdata; /* Both want windows */ else BEGIN rdata; } else { errpkt("Can't open file"); RESUME; } } B { ack(); reot(); sleep(2); RESUME; } /* Got End Of Trans. */ A { if ( rdattr(data)) ack(); /* Got file Attributes */ else { errpkt("Not enough disk space"); clsof(); RESUME; } } D { ack(); decode(data,putfil); /* First data packet */ if ( wdinit() ) BEGIN rwdata; else BEGIN rdata; } Z { ack(); reof(); BEGIN rfile; } /* Got End Of File */ Z { if ( !(cxseen || czseen) ) { /* Not aborted by me */ rweof(); } /* write data to disk */ pktnum = rpktno; /* make sure we have the right packet number */ ack(); reof(); BEGIN rfile; } D { if (cxseen) ack1("X"); /* Got data. */ else if (czseen) ack1("Z"); else ack(); decode(data,putfil); } D { if (cxseen || czseen) { /* Got data, in window */ pktnum = rpktno; /* Resynch. packet numbers */ if (czseen) ack1("Z"); else ack1("X"); ttflui(); sleep(3); ttflui(); } /* Flush input buffer */ else if ( !gwdata()) { wnderr("Protocol Error"); RESUME; } } N { if ( ! nackdp() ) { /* Got bad data, NACK it */ wnderr("Timed out."); /* Timed out, issue message and */ RESUME; } } /* clean up */ N { resend(); } /* Got a NAK, resend. */ Y { spar(data); /* Got ACK to Send-Init */ bctu = bctr; if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file"); RESUME; } } Y { if (canned(data)) { seof(); clsif(); BEGIN sseof; } else if (!sattr()) { /* Send Attr packet(s) */ BEGIN ssdata; } } Y { if (canned(data) || !sdata()) { /* Got ACK to data */ seof(); clsif(); BEGIN sseof; } else if (wdinit()) BEGIN swdata; } Y { if (canned(data) || !sdataw() ) { /* Got ACK, with Abort data */ if (!cxseen && !czseen && window ) { /* or abort by me or EOF */ BEGIN sweof; /* EOF but window not empty */ } else { pktnum = rpktno; /* Get the right number */ ttfluo(); sleep(2); ttflui(); /* Wait and flush buffer */ seof();clsif(); /* Send the Z packet */ BEGIN sseof; } } } N { if ( !wresnd() ) { /* Not an ACK, try resend */ wnderr("Timed out."); /* Timed out, issue message */ RESUME; } } /* and clean up */ Y { if ( weof() ) { /* If all the packets are ACKEd */ seof(); clsif(); /* End Of File state */ BEGIN sseof; } } Y { if (gnfile() > 0) { /* Got ACK to EOF, get next file */ if (sfile()) { if (filatr) { BEGIN ssattr; nxtcas = 1;} else BEGIN ssdata; } else { errpkt("Can't open file") ; RESUME; } } else { /* If no next file, EOT */ seot(); BEGIN sseot; } } Y { RESUME; } /* Got ACK to EOT */ E { ermsg(data); /* Error packet, issue message */ x = quiet, quiet = 1; /* close files silently */ clsif(); clsof(); quiet = x; RESUME; } . { nack(); } /* Anything else, send NAK */ %% /* P R O T O -- Protocol entry function */ proto() { int x; /* Set up the communication line for file transfer. */ if (local && (speed < 0)) { screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first"); return; } x = -1; if (ttopen(ttname,&x,mdmtyp) < 0) { debug(F111,"proto ttopen local",ttname,local); screen(SCR_EM,0,0l,"Can't open line"); return; } if (x > -1) local = x; debug(F111,"proto ttopen local",ttname,local); x = (local) ? speed : -1; if (ttpkt(x,flow) < 0) { /* Put line in packet mode, */ screen(SCR_EM,0,0l,"Can't condition line"); return; } sleep(1); /* The 'wart()' function is generated by the wart program. It gets a character from the input() routine and then based on that character and the current state, selects the appropriate action, according to the state table above, which is transformed by the wart program into a big case statement. The function is active for one transaction. */ wart(); /* Enter the state table switcher. */ screen(SCR_TC,0,0l,""); /* Transaction complete */ }