/***********************************************************************/ /* File KSEND.C - Send procedures for RML Kermit; Chris Kennington, RML. 1st July 1985 */ #define DEFS2 1 #define DEFS4 1 #include "stdio.h" #include "b:kext.h" /* static externals for this file only */ static char cannot[] = "Cannot open <%s>; "; static char mainhas[] = "Mainframe has "; static char unable[] = "Nothing from mainframe. "; static int num, len; /* Packet number & length */ gnxtfl() /* Get next file in a file group; if wildcard, expand it into cmdline. Return TRUE or FALSE. */ { char ret; if (filecount-- == 0) { filnam = 0; return(FALSE); /* If no more, fail */ } else { vtline(LOCFILE,filblank); vtline(LOCFILE,(filnam = *(filelist++))); printmsg(null); if ( ( (ret = fileok(filnam))&(char)0x07 ) != 0 ) { txtout("not sent."); /* no file */ return(gnxtfl()); /* recursive call */ } else if ( (ret&(char)0x40) != 0 ) { /* wildcards */ printf("Expanding wildcards ..."); ret = wildex(filnam,cmdline); printmsg("Will send: %s",cmdline); if (ret > (char)8) txtout(" (more on disk)"); filecount = decol8(cmdline,cmdparm,8); filelist = cmdparm; return(gnxtfl()); /* recursive call */ } else { return(TRUE); } } } /* end of gnxtfl() */ char sbreak() /* Send Break (EOT) */ { if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */ spack('B',n,0,0); /* Send a B packet */ switch (rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num<0 ? 63:num); /* unless NAK for previous packet, */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, fail */ inctry(); /* ++n%64 & ++tries */ printmsg("** All files sent OK. "); return('C'); /* Switch state to Complete */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in B */ default: /* Other, "abort" */ printmsg(badmsg,'Y',type); return('A'); } } /* end of sbreak() */ char sdata() /* Send File Data */ { if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spack('D',n,size,packet); /* Send a D packet */ if (abtflag != 0) { sendfail(); return('A'); } switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ if (list > 2) printf("\rDbg: NAK for packet %c.", tochar(num)); num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */ /* which is just like an ACK for this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, repeat */ inctry(); /* ++n%64 & ++tries */ if (len != 0) switch (*recpkt) { /* truncation */ case 'X': /* single file */ printmsg("%struncated file",mainhas); return('Z'); case 'Z': /* file group */ printmsg("%scancelled transfer",mainhas); seclose(); return('B'); default: if (list > 2) printf("\rDbg: Bad ACK <%s>",recpkt); break; } if ((size = bufill(packet)) == EOF) /* Get data from file */ if (errno == 0) return('Z'); /* If EOF set state to that */ else { /* error */ error(diskfail,errno); return('A'); } else return('D'); /* Got data, stay in state D */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ seclose(); return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in D */ case 'A': /* User abort */ sendfail(); return('A'); default: /* Anything else, just "abort" */ printmsg(badmsg,'Y',type); return('A'); } } /* end of sdata() */ seclose() /* close send-file */ { if (fp != 0) { kclose(fp); fp = 0; filnam = 0; } return; } /* end of seclose() */ sendfail() /* process user abort */ { abtflag = 0; rpack(&len,&num,recpkt); /* ignore next packet */ error(errmsg); /* then abort */ seclose(); return; } /* end of sendfail() */ sendsw(ist) /* Send files */ int ist; /* initial state */ { state = ist; n = 0; numtry = 0; while(TRUE) { if (list > 2) { outc(CR); printf("Dbg: sendsw() state: %c, ",state); } errdisp(); /* update error display */ switch(state) { case 'S': txtout(dots); state = sinit(); break; /* Send-Init */ case 'F': state = sfile(); break; /* Send file-init */ case 'D': state = sdata(); break; /* Send-Data */ case 'Z': state = seof(); break; /* Send-End-of-File */ case 'B': state = sbreak(); break; /* Send-Break */ case 'C': seclose(); return (TRUE); /* Complete */ case 'A': /* "Abort" */ default: /* Unknown, fail */ seclose(); return (FALSE); } } } /* end sendsw() */ char seof() /* Send End-Of-File. */ { if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ spack('Z',n,0,0); /* Send a 'Z' packet */ if (fp != 0) printmsg("** File %s sent OK. ",filnam); seclose(); /* close file */ switch(rpack(&len,&num,recpkt)) { case 'N': /* NAK, just stay in this state, */ num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, hold out */ inctry(); /* ++n%64 & ++tries */ fp = NULL; /* Set flag indicating no file open */ if (gnxtfl() == FALSE) /* No more files go? */ return('B'); /* if not, break, EOT, all done */ return('F'); /* More files, switch state to F */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in Z */ case 'A': /* User abort */ sendfail(); return('A'); default: /* Anything else, just "abort" */ printmsg(badmsg,'Y',type); return('A'); } } /* End of seof() */ char sfile() /* Send File Header. */ { char wk[14], *newfilnam, /* Pointer to file name to send */ c, *cp; /* char, pointer */ if (numtry++ > MAXTRY) { txtout(unable); return('A'); } if ( (fp == NULL) && ( (fp = kropen(filnam)) == NULL) ) { /* trouble opening file */ if (filecount != 0) { /* if more to go */ printf(cannot,filnam); gnxtfl(); numtry = 0; /* permit name message */ return('F'); /* send next one */ } else { error(cannot,filnam); return('A'); } } strcpy(wk, filnam); /* Copy file name */ newfilnam = &wk; if (newfilnam[1] == ':') newfilnam += 2; /* strip CP/M disk-letter */ /* Filenames are always u.c. under CP/M */ len = strlen(newfilnam); if (numtry == 1) /* once per file only */ printf("Sending <%s> as <%s>\r",filnam,newfilnam); if (abtflag != 0) { sendfail(); return('A'); } spack('F',n,len,newfilnam); /* Send an F packet */ switch(rpack(&len,&num,recpkt)) { case 'N': /* NAK, just stay in this state, */ num = (--num<0 ? 63:num); printmsg("Trouble exchanging params"); /* unless it's NAK for next packet which is just like an ACK for this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, stay in F state */ inctry(); /* ++n%64 & ++tries */ softeof = FALSE; if ( (size = bufill(packet)) == EOF ) { /* null file */ if (errno == 0) { printmsg("File empty."); return('Z'); /* on to next */ } else { /* error */ error(diskfail,errno); return('A'); } } else return('D'); /* Switch state to D */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ seclose(); return('A'); /* abort */ case FALSE: if (list != 1) txtout(trying); return(state); /* Receive failure, stay in F state */ case 'A': /* User abort */ sendfail(); return('A'); default: /* Anything else, just "abort" */ printmsg(badmsg,'Y',type); return('A'); } } /* end of sfile() */ char sinit() /* Send Initiate */ /* send this host's parameters and get other side's back.*/ { if (numtry++ > MAXTRY) { /* If too many tries, give up */ txtout(unable); return('A'); } len = spar(packet); /* Fill up init info packet */ flushinput(); /* Flush pending input */ spack('S',n,len,packet); /* Send an S packet */ if (abtflag != 0) { sendfail(); return('A'); } switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'Y': /* ACK */ if (n != num) /* If wrong ACK, stay in S state */ return(state); /* and try again */ rpar(recpkt,len); /* Get other side's init info */ compmode(); /* tell user */ if (eol == 0) eol = '\n'; /* Check and set defaults */ if (quote == 0) quote = '#'; inctry(); /* ++n%64 & ++tries */ return('F'); /* OK, switch state to F */ case 'I': /* Info-exchange */ rpar(recpkt,len); len = spar(packet); compmode(); spack('Y',n,len,packet); rpack(&len,&num,recpkt); /* ignore response */ return('S'); case 'R': /* Get-packet */ txtout("R-packet from remote Kermit "); rpar(recpkt,len); return(state); /* causes retransmission of 'S' */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Receive failure */ if (list != 1) txtout(trying); case 'N': /* NAK, try it again */ return(state); case 'A': /* User abort */ sendfail(); return('A'); default: /* Anything else, just "abort" */ printmsg(badmsg,'Y',type); return('A'); } } /* end of sinit() */ /********************* END of KSEND.C ****************************/