NetBSD/gnu/dist/gkermit/gproto.w

229 lines
6.3 KiB
C

/* 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 <stdio.h>
#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;
}
<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;
}
}
<ssfil>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;
}
}
<ssatt>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;
}
}
<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");
}
<sseof>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;
}
}
<sseot>Y { return(failure); } /* Send ACK to EOT - done */
/* Receiving states... */
v { tinit(); rinit(); BEGIN srini; } /* Start-state for Receive */
<srini>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 */
}
<srfil>B { ack(); return(failure); } /* Receive EOT packet */
<srfil>F { /* Receive File header packet */
if (rcvfil() < 0) {
errpkt("rcvfil");
} else {
encstr(filnam);
ack1(xdata);
streamon();
BEGIN sratt;
}
}
<sratt>A { /* Receive Attribute packet */
if (gattr(rdatap) == 0) {
ack();
} else {
ack1("\"");
}
}
<sratt>D { /* Receive first Data packet */
if (decode(datalen) < 0) {
errpkt("Packet decoding error");
} else {
ack();
BEGIN srdat;
}
}
<sratt>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 */
}
}
<srdat>D { /* Receive Data packet */
if (decode(datalen) < 0)
errpkt("Packet decoding error");
else
ack();
}
<srdat>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;
}
<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. */
%%