/* SWITCH_C - QL-Kermit protocol state switcher Based on ckcpro.w, (C) Columbia University */ /* Include files */ #include "ram1_ker_h" /* Kermit definitions */ #include "flp1_fcntl_h" /* File opening modes */ /* External variables */ extern int size; /* Current packet size */ extern int n; /* Current packet number */ extern int numtry; /* Retry count */ extern int oldtry; /* Saved retry count */ extern int debug; /* Debugging level */ extern int retry; /* Retry limit */ extern long filein; /* File bytes received */ extern long fileout; /* File bytes sent */ extern long totin; /* Batch bytes received */ extern long totout; /* Batch bytes sent */ extern bool toscr; /* Flag for screen output */ extern char sndpkt[]; /* Send packet data */ extern char recpkt[]; /* Received packet data */ extern char *newfilnam; /* Name of file created */ extern char *destdev; /* Default destination device */ extern char *sourdev; /* Default source device */ extern char *errdata; /* Data for E packet */ extern char stype; /* Server command */ extern char type; /* Current packet type */ extern char *cmarg,*cmarg2; /* Command arguments */ extern int fp; /* Transfer file */ extern int _oserr; /* QDOS error code */ extern int oserr; /* Copy of above */ extern bool warn8; /* Lost 8th bit warning given */ extern bool cxseen; /* File interrupt flag */ extern bool czseen; /* Batch interrupt flag */ extern int state; /* Current state */ /* External functions */ extern char *stname(); /* Printable state name */ /* Local variables */ int num; /* Packet number */ int len; /* Packet length */ int pt; /* Packet type */ static char ackd; /* Y packet data */ /* Switcher macros */ #define CHKTRY if (numtry++>retry) RERR #define SWREC switch (pt = rpack(&len,&num,recpkt)) #define NNXT n = (n+1)%64 #define NEXT(s) return(s) #define STAY return(state) #define GOT(c) case 'c': #define OTHER default: #define NONE case BAD: #define INTRPT case INTE: #define DONE return(COMP) #define STOP return(ABORT) #define QERR return(qdoserr()) #define PERR return(proterr()) #define IERR return(interrupt()) #define RERR return(rtlim()) /* SWITCHER - The state table switcher for all the Kermit actions. It loops until either it finishes, or an error is encountered. The routines called by switcher are responsible for changing the state, although the choice of which new state may also be influenced by the current Kermit command. The entry state is set by the user's command. */ bool switcher(start) int start; { newfilnam[0] = '\0'; /* Set up file name */ n = 0; /* Initialize packet number */ numtry = 0; /* No retries yet */ tinit(); /* Set up default Send-Init values */ state = start; /* Set up starting state */ flushinput(); /* Start each transaction clean */ forever /* Do this as long as necessary */ { if (debfull) debugst(); /* Log state and packet number */ if (state==ABORT) closef(); /* Clean up mess */ switch (state) { case ABORT: return(FALSE); /* Abort */ case COMP: return(TRUE); /* Complete */ case R_INIT: state = rinit(); endcase; /* Receive-Init */ case R_FILE: state = rfile(); endcase; /* Receive-File */ case R_DATA: state = rdata(); endcase; /* Receive-Data */ case S_INIT: state = sinit(); endcase; /* Send-Init */ case S_FILE: state = sfile(); endcase; /* Send-File */ case S_DATA: state = sdata(); endcase; /* Send-Data */ case S_EOF: state = seof(); endcase; /* Send-End-of-File */ case S_BRK: state = sbreak(); endcase; /* Send-Break */ case S_COMD: state = scomd(); endcase; /* Send-Command */ case G_INIT: state = ginit(); endcase; /* Get-Init */ case K_ERR: state = serr(); endcase; /* Send-Error */ default: error("Bad protocol state - %d",state); return(FALSE); /* Unknown state, fail */ } } } /* SERR - Send an error packet to remote machine */ int serr() { if (*errdata=='\0') /* If no error message, */ strcpy(errdata,"No description"); /* put in a default one */ spack('E',n,strlen(errdata),errdata); /* Send the error packet */ STOP; /* and end transaction */ } /* SCOMD - Send generic or system command to server */ int scomd() { int l; CHKTRY; /* Check retries */ printf("Sending command\n"); len = stclen(cmarg); /* Get length of command name */ spack(stype,0,len,cmarg); /* Send command packet */ SWREC /* What was the reply? */ { GOT(Y) if (stype=='G') DONE; /* Back to parser */ STAY; /* Try again otherwise */ GOT(S) rpar(recpkt); l = spar(sndpkt); spack('Y',n++,l,sndpkt); /* Get ready to receive */ toscr = TRUE; /* onto screen */ NEXT(R_DATA); /* any command output */ GOT(E) prerrpkt(recpkt); /* Error, print message */ STOP; GOT(N) STAY; /* NAK from server, keep trying */ GOT(B) if (num!=n) STOP; /* Need right packet number here */ ack(); /* Say OK */ STAY; /* and keep trying */ NONE nak(); /* Appease server to avoid error */ STAY; /* and try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* GINIT - Ask server for file */ int ginit() { int l; CHKTRY; /* Check retries */ printf("Asking server for %s\n",cmarg); len = stclen(cmarg); spack('R',0,len,cmarg); /* Send an R packet */ SWREC /* What was the reply? */ { GOT(S) rpar(recpkt); /* Get the other side's init data */ l = spar(sndpkt); /* Fill up packet with mine */ spack('Y',n,l,sndpkt); /* and ACK with my parameters */ NNXT; oldtry = numtry; /* Save old try count */ numtry = 0; /* Start a new counter */ NEXT(R_FILE); /* and enter Get-File state */ GOT(E) closef(); /* Clean up transfer file */ discard(newfilnam); /* and delete it */ prerrpkt(recpkt); /* Print error message */ STOP; GOT(N) STAY; /* NAK from server, keep trying */ GOT(B) if (num!=n) STOP; /* Need right packet number here */ ack(); /* Say OK */ STAY; /* and keep trying */ NONE nak(); /* Appease server to avoid error */ STAY; /* and try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* RINIT - Receive Initialization */ int rinit() { int l; CHKTRY; /* Check retries */ printf("Exchanging parameters\n"); SWREC /* Get a packet */ { GOT(S) rpar(recpkt); /* Get the other side's init data */ l = spar(sndpkt); /* Fill up packet with mine */ spack('Y',n,l,sndpkt); /* and ACK with my parameters */ oldtry = numtry; /* Save old try count */ numtry = 0; /* Start a new counter */ NNXT; NEXT(R_FILE); /* and enter Receive-File state */ GOT(E) closef(); /* Clean up file */ discard(newfilnam); /* and delete it */ prerrpkt(recpkt); /* Print error message */ STOP; NONE nak(); /* Return a NAK */ STAY; /* and keep trying */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* RFILE - Receive File Header */ int rfile() { int l; char file[30]; CHKTRY; /* Check retries */ SWREC /* Get a packet */ { GOT(S) if (oldtry++>retry) RERR; /* Check retries */ if (num==((n==0) ? 63 : n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again with */ l = spar(sndpkt); /* our Send-Init parameters */ spack('Y',num,l,sndpkt); numtry = 0; /* Reset try counter */ STAY; } else STOP; /* Not previous packet */ GOT(Z) if (oldtry++>retry) RERR; /* Check retries */ if (num==((n==0) ? 63 : n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again */ ackn(num); numtry = 0; STAY; } else STOP; /* Not previous packet */ GOT(F) if (num!=n) STOP; /* Must have right packet number */ if (strlen(cmarg2)==0) rtol(file,recpkt); else strcpy(file,cmarg2); /* Make new file name */ if ((fp = devopen(file,destdev,O_WRONLY|O_CREAT|O_TRUNC))<0) { error("Cannot create %s for receiving",file); QERR; } printf("Receiving %s as %s\n",recpkt,newfilnam); ack(); /* Acknowledge the file header */ oldtry = numtry; /* Reset try counters */ numtry = 0; toscr = FALSE; /* Data into a file */ filein = 0; /* Clear byte counter */ NNXT; NEXT(R_DATA); /* Switch to Data state */ GOT(X) if (num!=n) STOP; /* Screen data is coming */ toscr = TRUE; /* Set data destination */ bufemp(recpkt,len); /* Write the data to screen */ ack(); /* Acknowlege it */ oldtry = numtry; /* Reset the try counters */ numtry = 0; NNXT; NEXT(R_DATA); /* and continue to receive data */ GOT(B) if (num!=n) STOP; /* Need right packet number here */ ack(); /* Say OK */ printf("Received EOT, total %ld bytes\n",totin); n = 0; /* Reset packet counter */ DONE; /* and finish transaction */ GOT(E) closef(); /* Clean up file */ discard(newfilnam); /* and delete it */ prerrpkt(recpkt); /* Print error message */ STOP; NONE nak(); /* Return a NAK */ STAY; /* and keep trying */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* RDATA - Receive Data */ int rdata() { CHKTRY; /* Check retries */ SWREC /* Get a packet */ { GOT(D) if (num!=n) /* Right packet number? */ { if (oldtry++>retry) RERR; /* Check retries */ if (num==((n==0) ? 63 : n-1)) /* Check packet number */ { /* Previous packet again? */ ackn(num); /* Yes, re-ACK it */ numtry = 0; /* Reset try counter */ STAY; /* Don't write out data! */ } else STOP; /* Not previous packet */ } if (!bufemp(recpkt,len)) /* Write the data to file or screen */ { error("Write failure"); QERR; } if (cxseen) ack1("X"); /* Check interrupt flags */ else if (czseen) ack1("Z"); /* and send an */ else ack(); /* appropriate acknowlegement */ oldtry = numtry; /* Reset the try counters */ numtry = 0; NNXT; STAY; GOT(F) if (oldtry++>retry) RERR; /* Check retries */ if (num==((n==0) ? 63 : n-1)) /* Check packet number */ { ackn(num); /* ACK previous one again */ numtry = 0; /* Reset try counter */ STAY; } else STOP; /* Not previous packet */ GOT(Z) if (num!=n) STOP; /* Must have right packet number */ ack(); /* OK, ACK it */ printf("Received EOF, %ld bytes\n",filein); totin += filein; if (!toscr) { closef(); /* Close the file */ if (*recpkt=='D') /* Check for 'discard file' */ { discard(newfilnam); printf("File discarded by %s interrupt\n",(cxseen || czseen) ? "local" : "remote"); } } toscr = FALSE; /* Reset disposition flag */ NNXT; NEXT(R_FILE); /* and go back to Receive-File state */ GOT(E) closef(); /* Tidy up file */ discard(newfilnam); /* and delete it */ prerrpkt(recpkt); /* Print error message */ STOP; NONE nak(); /* Return a NAK */ STAY; /* and keep trying */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* SINIT - send this side's parameters and get other side's back */ int sinit() { int l; CHKTRY; /* Check retries */ printf("Exchanging parameters\n"); l = spar(sndpkt); /* Fill up init info packet */ spack('S',n,l,sndpkt); /* Send an S packet */ SWREC /* What was the reply? */ { GOT(N) STAY; /* NAK, try it again */ GOT(Y) if (n!=num) STAY; /* If wrong ACK, try again */ rpar(recpkt); /* Get other side's init info */ numtry = 0; /* Reset try counter */ NNXT; NEXT(S_FILE); /* and switch state to Send-File */ GOT(E) prerrpkt(recpkt); /* Print error message */ STOP; NONE STAY; /* Receive failure, try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* SFILE - Send File Header */ int sfile() { char file[30]; /* Name file is sent under */ CHKTRY; /* Check retries */ closef(); /* Ensure last file closed */ if ((fp = devopen(cmarg,sourdev,O_RDONLY))<0) { /* Open transfer file */ error("Cannot open %s for sending",cmarg); QERR; } if (strlen(cmarg2)==0) ltor(file,newfilnam); /* No remote name, use local one */ else strcpy(file,cmarg2); /* Remote name given, use that */ len = strlen(file); /* Get length of new filename */ printf("Sending %s as %s\n",newfilnam,file); warn8 = FALSE; /* Clear 8-bit warning flag, */ ackd = ' '; /* remote interrupt flag */ cxseen = FALSE; /* and file interrupt flag */ fileout = 0; /* Reset character count */ spack('F',n,len,file); /* Send an F packet */ SWREC /* What was the reply? */ { GOT(N) num = (--num<0 ? 63 : num); /* NAK, just stay in this state */ if (n!=num) STAY; /* unless it's NAK for next packet, */ /* which is just like an ACK for */ /* this packet so fall through */ GOT(Y) if (n!=num) STAY; /* If wrong ACK, stay here */ numtry = 0; /* Reset try counter */ NNXT; size = bufill(sndpkt); /* Get first data from file */ NEXT(S_DATA); /* and switch to sending state */ GOT(E) prerrpkt(recpkt); /* Print error message */ STOP; NONE STAY; /* Receive failure, try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* SDATA - Send File Data */ int sdata() { char r; /* Temporary */ CHKTRY; /* Check retries */ if (cxseen || czseen) NEXT(S_EOF); /* Interrupt from this end? */ spack('D',n,size,sndpkt); /* Send a D packet */ SWREC /* What was the reply? */ { GOT(N) num = (--num<0 ? 63 : num); /* NAK, just stay in this state */ if (n!=num) STAY; /* unless it's NAK for next packet */ /* which is just like an ACK for */ /* this packet so fall through */ GOT(Y) if (n!=num) STAY; /* If wrong ACK, try again */ numtry = 0; /* Reset try counter */ NNXT; if ((r = recpkt[0])=='X' || r=='Z') /* Interrupt from remote end? */ { ackd = r; /* Yes, save interrupt type */ NEXT(S_EOF); /* and go to send Z/D */ } size = bufill(sndpkt); /* Get data from file */ if (size==EOF) NEXT(S_EOF); /* If EOF set state to that */ else STAY; /* Got data, stay in send state */ GOT(E) prerrpkt(recpkt); /* Print error message */ STOP; NONE STAY; /* Receive failure, try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* SEOF - Send End-Of-File */ int seof() { CHKTRY; /* Check retries */ if (cxseen || czseen || ackd=='X' || ackd=='Z') printf("Sending discard (%s interrupt)\n",(cxseen || czseen) ? "local" : "remote"); else printf("Sending EOF, %ld bytes\n",fileout); totout += fileout; if (debon) printf("Closing input file\n"); closef(); /* Close the input file */ if (cxseen || czseen || ackd=='X' || ackd=='Z') spack('Z',n,1,"D"); else spack('Z',n,0,0); /* Send appropriate EOF */ SWREC /* What was the reply? */ { GOT(N) num = (--num<0 ? 63 : num); /* NAK, just stay in this state */ if (n!=num) STAY; /* unless it's NAK for next packet, */ /* which is just like an ACK for */ /* this packet so fall through */ GOT(Y) if (n!=num) STAY; /* If wrong ACK, try again */ numtry = 0; /* Reset try counter */ NNXT; NEXT(S_BRK); /* then finish transaction */ GOT(E) prerrpkt(recpkt); /* Print error message */ STOP; NONE STAY; /* Receive failure, try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* SBREAK - Send Break (end of transaction) */ int sbreak() { CHKTRY; /* Check retries */ printf("Sending EOT, total %ld bytes\n",totout); spack('B',n,0,0); /* Send a B packet */ SWREC /* What was the reply? */ { GOT(N) num = (--num<0 ? 63 : num); /* NAK, just stay in this state */ if (n!=num) STAY; /* unless it's NAK for next packet, */ /* which is just like an ACK for */ /* this packet so fall through */ GOT(Y) if (n!=num) STAY; /* If wrong ACK, try again */ numtry = 0; /* Reset try counter */ NNXT; DONE; /* Transaction complete */ GOT(E) prerrpkt(recpkt); /* Print error message */ STOP; NONE STAY; /* Receive failure, try again */ INTRPT IERR; /* CTRL-E interrupt */ OTHER PERR; /* Some other packet type */ } } /* DEBUGST - Log the state & expected packet number */ debugst() { printf("State %s, packet %d\n",stname(state),n); } /* PROTERR - An unexpected packet type received */ int proterr() { printf("PROTOCOL ERROR: %c packet in state %s\n",pt,stname(state)); strcpy(errdata,"Protocol error"); return(K_ERR); }