/* G P R O T O -- Protocol module for gkermit */ /* -*-C-*- */ /* Author: Frank da Cruz The Kermit Project Columbia University 612 West 115th Street New York NY 10025-7799 USA http://www.columbia.edu/kermit/ kermit@columbia.edu Copyright (C) 1999, The Trustees of Columbia University in the City of New York. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "gkermit.h" _MYPROTOTYPE( int closof, (void) ); /* Close output file */ _MYPROTOTYPE( VOID errpkt, (char *) ); /* Send Error packet */ extern char * xdata, *rdatap, **cmlist, *cmarg, *rpar(), strbuf[], filnam[]; extern int start, bctu, bctr, delay, cx, cz, failure, attributes, datalen; extern int streamok, streaming, timint; extern FILE * db; static int x; static VOID streamon() { /* Start streaming if negotiated */ x = 0; if (streamok > 0) { streaming = 1; timint = 0; } } /* Declare gwart states (like lex) */ %states ssini ssfil ssdat ssatt sseot sseof sipkt %states srini srfil srdat sratt /* Packets are read by the input() function, which returns the packet type */ /* that serves as the input to the state machine, which follows... */ %% /* Sending states... */ s { /* Start state for Send. */ tinit(); /* Initialize transaction. */ if (sinit('S') < 0) { errpkt("sinit"); } /* Build and send the S packet. */ else BEGIN ssini; } Y { /* Receive ACK to I packet */ spar(rdatap); /* Set parameters from it */ bctu = bctr; /* Switch to negotiated block check */ if (gnfile() > 0) { /* Is there a file to send? */ if (sfile() < 0) { /* Yes, open it, send F packet, */ errpkt("sfile"); } else { /* No error */ streamon(); BEGIN ssfil; } } else { /* No files to send, */ if (seot() < 0) { errpkt("seot"); } /* so send EOT packet. */ else BEGIN sseot; } } Y { /* Receive ACK to File header packet */ if (attributes) { /* If attributes negotiated */ if (sattr() < 0) { /* Send file attributes */ errpkt("sattr"); } else BEGIN ssatt; } else if ((x = sdata()) == 0) { /* Otherwise send first Data packet */ if (seof("") < 0) { /* Empty file - send EOF */ errpkt("seof"); } else { BEGIN sseof; } } else if (x < 0) { /* Error */ errpkt("sdata"); } else { /* OK - switch to Data state */ BEGIN ssdat; } } Y { /* Receive ACK to Attribute packet */ if (*rdatap == 'N') { /* Check for refusal */ seof("D"); BEGIN sseof; } else if ((x = sdata()) == 0) { /* Otherwise send first Data packet */ if (seof("") < 0) { /* Empty file - send EOF */ errpkt("seof"); } else { BEGIN sseof; } } else if (x < 0) { /* Error */ errpkt("sdata"); } else { /* OK - switch to Data state */ BEGIN ssdat; } } Y { /* Receive ACK to Data packet */ if (*rdatap == 'X') /* Check for file cancellation */ cx = 1; else if (*rdatap == 'Z') /* Check for batch cancellation */ cz = 1; if ((x = sdata()) == 0) { /* Send data packet if data left. */ if (seof((cx | cz) ? "D" : "") < 0) { /* If not, send Z packet */ errpkt("seof"); } else { BEGIN sseof; } } else if (x < 0) /* Fatal error sending data */ errpkt("sdata"); } Y { /* Receive ACK to EOF */ if (gnfile() > 0) { /* Get next file from list */ if (sfile() > 0) BEGIN ssfil; else { errpkt("sfile"); } } else { /* No more files */ seot(); /* Send EOT */ BEGIN sseot; } } Y { return(failure); } /* Send ACK to EOT - done */ /* Receiving states... */ v { tinit(); rinit(); BEGIN srini; } /* Start-state for Receive */ S { /* Receive S packet */ spar(rdatap); /* Set parameters from it */ ack1(rpar()); /* ACK with our parameters */ bctu = bctr; /* Switch to negotiated block check */ streamon(); BEGIN srfil; /* Wait for file or EOT */ } B { ack(); return(failure); } /* Receive EOT packet */ F { /* Receive File header packet */ if (rcvfil() < 0) { errpkt("rcvfil"); } else { encstr(filnam); ack1(xdata); streamon(); BEGIN sratt; } } A { /* Receive Attribute packet */ if (gattr(rdatap) == 0) { ack(); } else { ack1("\""); } } D { /* Receive first Data packet */ if (decode(datalen) < 0) { errpkt("Packet decoding error"); } else { ack(); BEGIN srdat; } } Z { /* Empty file */ if (*rdatap == 'D') /* Check for Discard directive */ cx = 1; if (closof() < 0) { /* Close the output file */ errpkt("closof"); } else { ack(); /* Send ACK */ BEGIN srfil; /* Wait for another file or EOT */ } } D { /* Receive Data packet */ if (decode(datalen) < 0) errpkt("Packet decoding error"); else ack(); } Z { /* Receive EOF packet */ if (*rdatap == 'D') /* Check for Discard directive */ cx = 1; if (closof() < 0) { /* Close the output file */ errpkt("closof"); } else { ack(); /* Send ACK */ BEGIN srfil; /* Wait for another file or EOT */ } } /* GET files from a Kermit server... */ r { /* Start state for Get */ tinit(); /* Initialize transaction */ ginit(); /* Initialize Get */ sinit('I'); /* Send I packet */ BEGIN sipkt; } Y { /* Receive ACK for I packet */ spar(rdatap); /* Set parameters from it */ if (scmd('R',cmarg) < 0) /* Send GET packet file filespec */ errpkt("scmd"); else BEGIN srini; /* Wait for S packet */ } E { return(failure = 1); } /* Receive an Error packet */ . { errpkt("Unknown packet type"); } /* Handle unwanted packet types. */ %%