/************************************************************************ * * HD6PRI.C Superkermit protocol modules and primitives. * ***********************************************************************/ #include "hd6ker.h" /* * r d a t a * * Receive data * The receiving of file attribute packets is handled in this module! * */ char rdata() { int num, len; /* Packet number, length */ unsigned int j; unsigned int k_size = 0; char *bufp, *start, c, d; /* attribute pointers */ float byte_size; double byte_sz, atof(); char filnam1[50]; /* Holds the converted file name */ if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,packet)) /* Get packet */ { /* code added to ACK and use attrib packets if received [FRANK DREANO] */ case 'A': if (num != n) { /* Right packet number or not */ if (oldtry++ > MAXTRY) return('A'); /* too many retries, abort */ if (num == ((n==0) ? 63:n-1)) { /* duplicate ? */ spack('Y',num,0,xnull); /* Yes, re-ACK it */ numtry = 0; /* Reset try counter */ return(state); /* stay in this state */ } else return('A'); } /* got the right attrib packet */ spack('Y',n,0,xnull); /* ACK the attribute */ oldtry = numtry; /* Reset try counters */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* bump packet counter */ bufp = packet; while ((*bufp) != '\0') { /* process the attributes */ switch(*bufp++) { case '1': d = *bufp; j = (*bufp) - ' '; *bufp = '+'; start = bufp; byte_sz = 0; bufp = ++bufp + j; c = *bufp; *bufp = ' '; /* terminate flting point string */ byte_sz = atof(start); if (debug) fprintf(dfp,"\nThe file size is: %7.f bytes.\n", byte_sz); *bufp = c; *start = d; break; case '#': /* just eat all other non-file size attribs */ case '.': j = (*bufp++) - ' '; bufp = bufp + j; break; case '!': j = (*bufp++) - ' '; start = bufp; k_size = 0; bufp = bufp + j; c = *bufp; *bufp = '\0'; /* terminate integer string */ k_size = atoi(start); if (debug) fprintf(dfp,"\nThe file size is: %u Kilobytes.\n", k_size); *bufp = c; break; default: j = (*bufp++) - ' '; bufp = bufp + j; if (debug) fprintf(dfp,"\nThe attribute is not recognized."); break; } /* end switch */ } /* end while */ /* got the incoming file size lets make contiguous efficient space */ if ((k_size == 0) && (byte_sz != 0)) k_size = byte_sz / 1000; k_size = 32 * ((k_size + 32 - 1)/32); /* round out */ k_size = k_size * 2; getfiles[49] = 0; strcpy(filnam1, getfiles); /* Copy filename */ if (k_size > 64) { if (debug) fprintf(dfp,"\nCI growth size is: %u.\n", k_size); fclose(fp); sprintf(cmdstg,">SYSLIB2>MFA %s -GRSZ %u ", filnam1, k_size); if ((cmdstat = system(cmdstg)) != 0) fprintf(stderr,"\nCould not modify <%s> growth size.", filnam1); if ((fileimage == FOREIGN) || (fileimage == BINARY)) fp = fopen(filnam1,"ab"); else fp = fopen(filnam1, "a"); } /* end if */ if (fileimage == FOREIGN) { /* stuff the attributes in the files */ sprintf(cmdstg,"%s\n",packet); fputs(cmdstg, fp); } /* end of attribute decoding and use [FRANK DREANO] */ return('D'); /* stay in this state */ case 'D': /* Got Data packet */ if (num != n) /* Right packet? */ { /* No */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries, abort */ if (num == ((n==0) ? 63:n-1)) { /* duplicate? */ spack('Y',num,0,xnull); /* Yes, re-ACK it */ numtry = 0; /* Reset try counter */ return(state); /* Don't write out data! */ } else return('A'); /* sorry, wrong number */ } /* Got data with right packet number */ if ( (num = decode(packet,len)) != 0 ) { error("Trouble writing file, OS code %xx",num); return('A'); } spack('Y',n,0,xnull); /* Acknowledge the packet */ n = (n+1)%64; /* Bump packet number, mod 64 */ oldtry = numtry; /* Reset the try counters */ numtry = 0; /* ... */ return('D'); /* Remain in data state */ case 'F': /* Got a File Header */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ if (num == ((n==0) ? 63:n-1)) /* Else check packet number */ { /* It was the previous one */ spack('Y',num,0,xnull); /* ACK it again */ numtry = 0; /* Reset try counter */ return(state); /* Stay in Data state */ } else return('A'); /* Not previous packet, "abort" */ case 'Z': /* End-Of-File */ if (num != n) return('A'); /* Must have right packet number */ spack('Y',n,0,xnull); /* OK, ACK it. */ fflush(fp); /* Flush all buffers */ fclose(fp); /* Close the file */ fp = NULL; /* if attributes were used shrink file then reset growth size */ if ((senda) && (sattrib)) { sprintf(cmdstg,">SYSLIB2>SHRINK %s", filnam1); system(cmdstg); sprintf(cmdstg,">SYSLIB2>MFA %s -GRSZ 20", filnam1); if ((cmdstat = system(cmdstg)) != 0) fprintf(stderr,"\nCould not reset <%s> growth size.", filnam1); } if (debug) { if ( (len != 0) && (*packet == 'D') ) fprintf(dfp, "\nFile <%s> truncated by local Kermit\n",filnam); else fprintf(dfp,"\nFile <%s> received OK\n",filnam1); } n = (n+1)%64; /* Bump packet number */ return('F'); /* Go back to Receive File state */ case 'E': /* Error packet received */ prerrpkt(packet); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Didn't get packet */ spack('N',n,0,xnull); /* Return a NAK */ return(state); /* Keep trying */ default: error(badpack,prompt,type); return('A'); /* Some other packet, "abort" */ } } /* End of rdata() */ /* * r f i l e * * Receive file header * */ char rfile() { int num, len; /* Packet number, length */ char filnam1[50]; /* Holds the converted file name */ if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,packet)) /* Get a packet */ { case 'S': /* Send-Init, maybe our ACK lost */ if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */ if (num == ((n==0) ? 63:n-1)) { /* Previous packet, mod 64? */ len = spar(packet); /* our Send-Init parameters */ spack('Y',num,len,packet); numtry = 0; /* Reset try counter */ return(state); /* Stay in this state */ } else return('A'); /* Not previous packet, "abort" */ case 'Z': /* End-Of-File */ if (oldtry++ > MAXTRY) return('A'); if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again. */ spack('Y',num,0,xnull); numtry = 0; return(state); /* Stay in this state */ } else return('A'); /* Not previous packet, "abort" */ case 'F': /* File Header (just what we want) */ if (num != n) return('A'); /* The packet number must be right */ decfil(packet, getfiles, len); /* 'unrepeat' filename */ getfiles[49] = 0; /* terminate the string */ strcpy(filnam1, getfiles); /* Copy filename */ if (filnamcnv) { /* Convert upper case to lower */ for (filnam=filnam1; *filnam != '\0'; filnam++) if (*filnam >= 'A' && *filnam <= 'Z') *filnam |= 040; filnam = filnam1; } /* should have gotten a file attribute packet instead */ /* if ((fileimage == FOREIGN) && ((senda == FALSE) || (sattrib == FALSE))) { error(noattrib, prompt); return('A'); } */ for (filnam=filnam1; *filnam != '\0'; filnam++) if (*filnam == ',') { *filnam++ = '\0'; *filnam = '\0'; break; } /* end for */ filnam = filnam1; if ((fileimage == BINARY) || (fileimage == FOREIGN)) { /* create and open binary/foreign type file */ if (debug) fprintf(dfp, "\nDeleting <%s> if it exists.",filnam1); sprintf(cmdstg,">SYSLIB2>DL %s -BF", filnam1); if ( ((cmdstat = system(cmdstg)) !=0) && (debug) ) fprintf(dfp, "\nFile not deleted; as it did not already exist."); cmdstat = 0; if (fileimage == BINARY) sprintf(cmdstg, ">SYSLIB2>CR %s -F_REL -LRSZ %d -SZ 0", filnam1, lrsz_6); if (fileimage == FOREIGN) sprintf(cmdstg, ">SYSLIB2>CR %s -SEQ -DATA_CODE BINARY -SZ 0", filnam1); if ((cmdstat = system(cmdstg)) != 0) { syserr("system"); return('A'); } /* end if */ if (debug) fprintf(dfp,"\nOpening <%s> for receiving.",filnam1); fp=fopen(filnam1,"ab"); } /* end if */ else { /* open ASCII type file */ if (dlflag) { /* overwrite existing file if flag set */ if (debug) fprintf(dfp, "\nDeleting <%s> if it exists.",filnam1); sprintf(cmdstg,">SYSLIB2>DL %s ", filnam1); if ( ((cmdstat = system(cmdstg)) !=0) && (debug) ) fprintf(dfp,"\nFile not deleted; as it did not already exist."); } /* end if */ if (debug) fprintf(dfp, "\nOpening <%s> for receiving.",filnam1); fp=fopen(filnam1,"a"); } /* end else */ if (fp == NULL) { error("%sCannot create <%s>",prompt,filnam1); return('A'); } /* end if */ else /* OK, give message */ if (debug) fprintf(dfp,"\nReceiving %s as %s",packet,filnam1); /* stuff dummy attribute in foreign file if the PC didn't send any */ if ((fileimage == FOREIGN) && ((senda == FALSE) || (sattrib == FALSE))) fputs(",I\n", fp); spack('Y',n,0,xnull); /* Acknowledge the file header */ oldtry = numtry; /* Reset try counters */ numtry = 0; /* ... */ n = (n+1)%64; /* Bump packet number, mod 64 */ return('D'); /* Switch to Data state */ case 'B': /* Break transmission (EOT) */ if (num != n) return ('A'); /* Need right packet number here */ spack('Y',n,0,xnull); /* Say OK */ if (debug) fprintf(dfp,"All files received\n"); return('C'); /* Go to complete state */ case 'E': /* Error packet received */ prerrpkt(packet); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Didn't get packet */ spack('N',n,0,xnull); /* Return a NAK */ return(state); /* Keep trying */ default: error(badpack,prompt,type); return ('A'); /* Some other packet, "abort" */ } } /* End rfile() */ /* * r i n i t * * Receive initalization * */ char rinit() { int len, num; /* Packet length, number */ bctu = 1; /* type-1 blk chk at first */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ switch(rpack(&len,&num,packet)) /* Get a packet */ { case 'S': /* Send-Init */ rpar(packet,len); len = spar(packet); spack('Y',n,len,packet); /* ACK with my parameters */ oldtry = numtry; /* Save old try count */ numtry = 0; /* Start a new counter */ n = (n+1)%64; /* Bump packet number, mod 64 */ bctu = bctr; /* use agreed blk chk type */ return('F'); /* Enter File-Receive state */ case 'E': /* Error packet received */ prerrpkt(packet); /* Print it out and */ return('A'); /* abort */ case 'I': /* Init-parameters */ rpar(packet,len); len = spar(packet); spack('Y',n,len,packet); /* ack with our parameters */ n = (n+1)%64; /* Bump packet number, mod 64 */ bctu = bctr; /* use agreed block check type */ return(state); /* & continue */ case FALSE: /* Didn't get packet */ spack('N',n,0,xnull); /* Return a NAK */ return(state); /* Keep trying */ default: error(badpack,prompt,type); return('A'); /* Some other packet type, "abort" */ } } /* End rinit() */ /* * r p a c k * * Read a packet * Modified for extended packets [FRANK DREANO] */ rpack(len,num,data) int *len, *num; /* Packet length and number */ char *data; /* Packet data */ { int j,i,done,k,s; /* Data character number, loop exit */ register char *bufp, *datap; /* 'fast' array indexes */ int maxlx1, maxlx2; /* extended packet length */ unsigned char pcb[4]; /* block check char array */ char t, /* Current input character */ rlongp, /* extended packet flag */ buffer[MAXPACKSIZ + 6]; /* area to do CRC block checks */ timoset(timint); /* set timeout */ /* The way timeouts are handled is that the flag stays clear, indicating that a timeout has occurred, until it is set to a value again by the next call to timoset(). This means that the effect can run up thro' the procedures without using longjmp(). */ rlongp = FALSE; t = 0; *len = 0; /* in case times out */ while (t != SOH) { /* Wait for packet header */ t = cread() & (char)0x7f; } timocan(); done = FALSE; /* Got SOH, init loop */ while (!done) /* Loop to get a packet */ { t = cread(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ bufp = buffer; /* init buffer pointer */ *bufp++ = t; /* Start the checksum */ *len = unchar(t) - bctu - 2; /* Character count */ if (*len == -(bctu+2)) rlongp = TRUE; /* long packets */ t = cread(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ *bufp++ = t; /* Update checksum */ *num = unchar(t); /* Packet number */ t = cread(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ *bufp++ = type = t; /* Update checksum */ /* extended packet modifications [FRANK DREANO] */ if (rlongp == TRUE) { t = cread(); if (t == SOH) continue; *bufp++ = maxlx1 = t; /* Get extended length */ t = cread(); if (t == SOH) continue; *bufp++ = maxlx2 = t; /* Get extended length */ t = cread(); if (t == SOH) continue; /* got all of extended packet header; do checksum and length computes */ *bufp = '\0'; if (t != tochar(chk1(buffer))) { /* compute hdr sum */ if (debug) fprintf(dfp, "\nExtended hdr chksum error: rec'd %xx computed %xx;", t, tochar(chk1(buffer))); return(FALSE); } /* end if */ *bufp++ = t; *len = unchar(maxlx1) * 95 + unchar(maxlx2) - bctu; } /* end if */ datap = data; for (i=0; i<*len; i++) { /* The data itself, if any */ t = cread(); /* Get character */ if (t == SOH) break; /* Resynch if SOH */ *bufp++ = *datap++ = t; /* Update checksum */ } if (t == SOH) continue; *bufp = *datap = '\0'; /* Terminate the strings */ /* At this point the data for an entire packet should have been read in */ /* so print it and do the block checks...type 1, 2, or 3. [FRANK DREANO] */ if (debug) fprintf(dfp,"\n Packet %d received; ",*num); if (debug>1) { /* Display incoming packet */ fprintf(dfp," type: %c;",type); fprintf(dfp," num: %d;",*num); fprintf(dfp," len: %d.",*len); if (*len != 0) { j = 0; while (j < *len) { fprintf(dfp,"\n data: <"); i=0; while ((i < 60 ) && (j < *len)) { putc(data[j++],dfp); i++; } /* end while */ putc('>',dfp); } } } for (s=0; s 0) { p = data[len]; switch (len) { /* for each parameter */ case 0: /* MAXL */ rpsiz = unchar(p); /* loop goes backwards so set spsiz to what was negotiated */ spsiz = (spsiz < 95) ? rpsiz : spsiz; break; case 1: /* TIME */ timint = (unchar(p) < 5) ? 5 : unchar(p); break; case 2: /* NPAD */ pad = unchar(p); break; case 3: /* PADC */ padchar = ctl(p); break; case 4: /* EOL */ eol = unchar(p); break; case 5: /* QCTL */ quote = p; break; case 6: /* QBIN */ if (image == 2) { if (p == 'Y') qu8 = '&'; else if (isalnum(p) == 0) /* provided punctuation */ qu8 = p; else image = 0; break; } break; case 7: /* BLOCK CHECK TYPE */ bctr = p - '0'; bctr = (bctr < 1 || bctr > 3) ? 1 : bctr; break; case 8: /* REPT */ if (p == '~') rptflg = TRUE; break; /* extended packet additions [FRANK DREANO] This routine sets 2 variables slongp = TRUE/FALSE for extended packets on/off and spsiz = negotiated packet length. */ case 9: if (slongp == TRUE) { /* did user ask for extended packets ? */ if (((unchar(p) & 0x02)) == 0x02) { spsiz = MAXPACKSIZ; /* 2000 bytes */ rpsiz = 500; /* set default extended packet length */ if (olen > 9) rpsiz = unchar(data[11]) * 95 + unchar(data[12]); /* set final negotiated size no matter what */ spsiz = (spsiz < rpsiz) ? spsiz : rpsiz; if (debug) fprintf(dfp,"\nExtended packets used size: %d.", spsiz); } /* end if */ else slongp = FALSE; /* turn extended packets off */ } /* end if */ /* if CAPAS bit not set */ if (((unchar(p) & 0x08)) == 0x08) /* user likes attrib packets */ sattrib = TRUE; break; default: /* CHKT, CAPAS etc. */ break; } } /* end while & outer switch */ if ( (qu8 == 0) && (image == 2) ) /* invalid tseting */ image = 0; if (debug) fprintf(dfp, "\nParms recd in: Fileimage: %d, image: %d, q_char: %c, rptflg: %s, bchk: %d.", fileimage,image,qu8,logicval[-rptflg],bctr); /* "\nParms rec'd in: 8th-bit tseting is %d, char is %c, reptflag %s, chktype %d.", image,qu8,logicval[-rptflg],bctr); */ return; } /* End of rpar() */ /* * s b r e a k * * Send break (EOT) * */ char sbreak() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */ spack('B',n,0,packet); /* 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, */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, fail */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* and bump packet count */ return('C'); /* Switch state to Complete */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return('C'); /* Receive failure, count as OK */ /* If timed out or etc. when completing, likely other end has gone away */ default: error(badpack,prompt,type); return ('A'); /* Other, "abort" */ } } /* End sbreak() */ /* * s d a t a * * Send file data * */ char sdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spack('D',n,size,packet); switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num<0 ? 63:num); /* unless it's NAK for next packet */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, persist */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ if (len != 0) switch (*recpkt) { /* ACK has data */ case 'Z': /* cancel all */ case 'z': filecount = 0; /* no more to go */ case 'X': /* cancel file */ case 'x': return('Z'); default: /* invalid */ if (!senda) { /* Attrib ACK can have data */ recpkt[20] = 0; /* truncate */ error("%sLocal Kermit sent ACK with data: <%s> - goodbye!",prompt,recpkt); return('A'); } /* end if */ } /* end inner switch */ if ((size = bufill(packet)) != EOF) /* data from file */ return('D'); /* Got data, stay in state D */ /* EOF can mean either really end-of-file or an error */ if ( (num = filerr()) != 0 ) { /* actual error */ error("Problem while reading file, OS code %xx",num); return('A'); } /* end if */ return('Z'); /* EOF */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in D */ default: error(badpack,prompt,type); return('A'); /* Anything else, "abort" */ } /* end outer switch */ } /* End sdata() */ /* * s e o f * * Send End-of-File * */ char seof() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ spack('Z',n,0,packet); /* Send a 'Z' packet */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) return(state); /* If wrong ACK, hold out */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* and bump packet count */ if (debug) fprintf(dfp,"\nClosing input file <%s>, ",filnam); fclose(fp); /* Close the input file */ fp = NULL; /* Set flag indicating no file open */ if (debug) fprintf(dfp,"looking for next file..."); if (gnxtfl() == FALSE) { /* No more files go? */ if (debug) fprintf(dfp,"\nNo more files to send."); return('B'); /* if not, break, EOT, all done */ } if (debug) fprintf(dfp,"New file is %s\n",filnam); senda = TRUE; /* send attrib pkt if negotiated */ 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 */ default: error(badpack,prompt,type); return('A'); /* Something else, "abort" */ } } /* End seof() */ /* * s f i l e * * Send file header * */ char sfile() { int num, len, lenlen; /* Packet number, length */ unsigned filesize; char filnam1[50], /* Converted file name */ *newfilnam, /* Pointer to file name to send */ *cp; /* char pointer */ /* MUST use attribute packets with foreign file types!! */ /* if ((fileimage == FOREIGN) && ((senda == FALSE) || (sattrib == FALSE))) { error(noattrib, prompt); return('A'); } */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ if (fp == NULL) { /* If not already open, */ if (debug) fprintf(dfp,"\nOpening %s for sending.",filnam); if ((fileimage == BINARY) || (fileimage == FOREIGN)) fp = fopen(filnam,"rb"); else fp = fopen(filnam,"r"); /* open the file to be sent */ if (fp == NULL) /* If bad file pointer, give up */ { error("%sCannot open file <%s>",prompt,filnam); return('A'); } } strcpy(filnam1, filnam); /* Copy file name */ newfilnam = cp = filnam1; while (*cp != '\0') /* Strip off all leading directory */ if (*cp++ == '>') /* names (ie. up to the last >). */ newfilnam = cp; if (filnamcnv) /* Convert lower case to upper */ for (cp = newfilnam; *cp != '\0'; cp++) if (*cp >= 'a' && *cp <= 'z') *cp ^= 040; len = cp - newfilnam; /* Compute length of new filename */ if (debug) fprintf(dfp,"\nSending %s as %s",filnam,newfilnam); if (iflg >= 99) spack('X',n,len,newfilnam); /* Send an X packet if a 'remote' cmd */ else spack('F',n,len,newfilnam); /* Send an F packet for file xfer */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { 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, stay in F state */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ /* if using attributes switch to 'Q' state; else 'D' state */ /* get the attribute from foreign files */ if (fileimage == FOREIGN) fgets(attrib, 80, fp); if ((sattrib) && (senda)) { /* use attribute packets */ if ( (fileimage == FOREIGN) && ((strncmp(",I",attrib,2)!=0)) ) { size = strlen(attrib)-1; /* drop the newline */ } else { /* not 'foreign' so build some attribs */ lenlen = 0; while (lenlen < 45) attrib[lenlen++] = 0x0000; /* compute size in Kilobytes */ if (fileimage == BINARY) filesize = fsize(filnam,0); else filesize = 0; sprintf(attrib, "%u", filesize); lenlen = strlen(attrib); /* print to string, include computer attrib as well */ sprintf(attrib, ".\042E3!%c%u", tochar(lenlen), filesize); size = strlen(attrib); } /* end else */ return('Q'); } else { /* not using attributes! */ if ((size = bufill(packet)) != EOF) /* data from file */ return('D'); /* Got data, stay in state D */ /* EOF can mean either really end-of-file or an error */ if ( (num = filerr()) != 0 ) { /* actual error */ error("Problem while reading file, OS code %xx",num); return('A'); } return('Z'); /* EOF (empty file) */ } /* end outer else */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in F state */ default: error(badpack,prompt,type); return('A'); /* Something else, just "abort" */ } } /* End sfile() */ /* * s a t t r u * * Send file attributes * A separate state is not required to receive file attributes ! * */ char sattru() { int num, len, lenlen; /* Packet number, length */ spack('A',n,size,attrib); /* Send an A packet for file xfer */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { 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, stay in Q state */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ if ((size = bufill(packet)) != EOF) /* data from file */ return('D'); /* Got data, stay in state D */ /* EOF can mean either really end-of-file or an error */ if ( (num = filerr()) != 0 ) { /* actual error */ error("Problem while reading file, OS code %xx",num); return('A'); } return('Z'); /* EOF (empty file) */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in Q state */ default: error(badpack,prompt,type); return('A'); /* Something else, just "abort" */ } } /* End sattru() */ /* * s i n i t * * Send initialization parameters and receive other side's back * */ char sinit() { int num, len; /* Packet number, length */ flushinput(); /* Flush pending input */ bctu = 1; /* assume type-1 block check */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ len = spar(packet); /* Fill up init info packet */ spack('S',n,len,packet); /* Send an S packet */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': num = (--num<0 ? 63:num); /* unless it's NAK for next packet */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ 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 */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ bctu = bctr; /* use agreed upon block check */ return('F'); /* OK, switch state to F */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case 'I': /* Init-parameters */ rpar(packet,len); len = spar(packet); spack('Y',n,len,packet); /* ack with our parameters */ n = (n+1)%64; /* Bump packet number, mod 64 */ bctu = bctr; /* use agreed upon block check */ return(state); /* & continue */ case FALSE: return(state); /* Receive failure, try again */ default: error(badpack,prompt,type); return('A'); /* Anything else, just "abort" */ } } /* End sinit() */ /* * s p a c k * * Send a packet * Modified for extended packets [FRANK DREANO] */ spack(stype,num,len,d) char stype, *d; int num, len; { int i, j; /* Character loop counter */ register char *bufp; char chksum, buffer[MAXPACKSIZ + 6], *lp; /* Checksum, packet buffer */ if (debug > 1) { /* Display outgoing packet */ fprintf(dfp,"\nSending packet; type: %c;",stype); fprintf(dfp," num: %d;",num); fprintf(dfp," len: %d;",len); if (len != 0) { j = 0; while (j < len) { fprintf(dfp,"\n data: <"); i=0; while ((i < 60 ) && (j < len)) { putc(d[j++],dfp); i++; } /* end while */ putc('>',dfp); } } } bufp = buffer; *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */ lp = bufp++; /* store LEN pointer for later */ *bufp++ = tochar(num); /* Packet number */ *bufp++ = stype; /* Packet type */ j = len + bctu; /* packet length plus block check characters */ if (j+2 > 94) { /* if (j > 95) { long packets */ *lp = tochar(0); /* init LEN count */ *bufp++ = tochar(j / 95); /* high part */ *bufp++ = tochar(j % 95); /* lo part */ *bufp = '\0'; /* header checksum */ *bufp++ = tochar(chk1(lp)); } else *lp = tochar(j+2); /* give normal length */ while (len-- > 0) *bufp++ = (*d++); *bufp = '\0'; switch (bctu) { case 1: *bufp++ = tochar(chk1(lp)); break; case 2: j = chk2(lp); *bufp++ = (unsigned) tochar((j >> 6) & 077); *bufp++ = (unsigned) tochar(j & 077); break; case 3: j = chk3(lp); *bufp++ = tochar(( (unsigned) (j & 0170000)) >> 12); *bufp++ = tochar((j >> 6) & 077); *bufp++ = tochar(j & 077); break; } *bufp++ = eol; /* *bufp = CR; CR for network */ write(1, buffer, bufp-buffer+1); if (debug) { fprintf(dfp," Packet %d sent;\n",num); } return; } /* End of spack() */ /* * s p a r * * Fill the data array with my send-init parameters * Returns length of parameter block (6, 7, 9 or 13) * Modified for extended packets [FRANK DREANO] */ spar(data) char *data; { char len; data[0] = tochar((spsiz > 94) ? 94 : spsiz); data[1] = tochar(MYTIME); data[2] = tochar(MYPAD); data[3] = ctl(0); data[4] = tochar(MYEOL); data[5] = MYQUOTE; len = 6; if (image == 2) { /* 8th-bit prefixing */ if (qu8 == 0) /* data[6] = 'Y'; this means I don't need to quote !!! */ data[6] = '&'; else data[6] = qu8; /* feed back 8-quote */ len = 7; } else data[6] = 'N'; data[7] = bctr + '0'; /* set checksum type */ len = 8; if (rptflg) { data[8] = '~'; /* only ~ for repeating */ len = 9; } /* end if */ /* extended packet modifications [FRANK DREANO] */ data[9] = tochar(0x08); /* I can accept attribute packets */ if (slongp == TRUE) { data[9] = tochar(0x0a); /* attribs & extended packets can be used */ data[10] = tochar(0x00); /* NO sliding windows! */ data[11] = tochar(MAXPACKSIZ / 95); /* set up for 2000 bytes */ data[12] = tochar(MAXPACKSIZ % 95); len = 13; if (debug) fprintf(dfp,"\nExtended packets requested (2000) bytes."); } /* end if */ if (debug) fprintf(dfp, "\nParms sent out: Fileimage: %d, image: %d, q_char: %c, rptflg: %s, bchk: %d.", fileimage,image,qu8,logicval[-rptflg],bctr); /* "\nParms sent out: 8th-bit tseting is %d, char is %c, reptflag %s, chktype %d.", image,qu8,logicval[-rptflg],bctr); */ return(len); } /* End of spar() */ /* * t i m o c a n * * Cancel a scheduled timeout * */ timocan() { timoset(0); timflag = 0xff; return; } /* End of timocan() */ /* * t i m e o x * * Indicate timeout condition * */ timoex() { timflag = 0; /* clear flag */ if (debug) { fprintf(dfp,"Timeout ..."); } return; } /* End of timoex() */ /* * f s i z e * * This routine gets the APPROXIMATE size of a file in kilobytes * so that an 'attribute' packet may be sent during transfers. * It uses very esoteric code and MOD400 macro calls so if it * causes trouble, skip sending attribute packets. * If the 'func' arg is other than '1' the size is only computed * for fixed-length record files as variable-length record file * size estimates are highly inaccurate. If the 'func' arg is '1' * AND the file 'fname' contains variable length records a 0 is * returned if the DATA_CODE is unknown and a 1 if it is BINARY. * * [FRANK DREANO] */ unsigned fsize(fname, func) char *fname; int func; { #define $GIFIL 0x1060 /* --- get file information --- */ struct mcl_psb { int *reg_b4; int *reg_b3; int *reg_b2; int *reg_b1; int reg_r7; int reg_r6; int reg_r5; int reg_r4; int reg_r3; int reg_r2; } reg; union cvt_adr {int address[3]; int *adrint; char *adrchar;} adrtag; struct gifab { int gfa_lrsz; /* logical record size */ int gfa_bksz; /* block size (bytes/CI for disk files) */ int gfa_find; /* field indicators (# of CIs in file) */ int gfa_dsw1; /* device specific word 1 */ int gfa_dsw2; /* device specific word 2 */ int gfa_isw1; /* init device specific word 1 */ int gfa_isw2; /* init device specific word 2 */ int gfa_rfu [9]; /* reserved - must be zero */ } fab; # define gfa_cisz gfa_bksz struct gipsb { int gipsb_lfn; int *gipsb_pthp; int gipsb_dtyp; int gipsb_lrn; char gipsb_ftyp; char gipsb_rtyp; struct gifab *gipsb_fabp; unsigned int gipsb_sdid; int gipsb_resv; int *gipsb_kdp; int gipsb_rdsz; int gipsb_nrf; } psb; int i; int hunds, tens, units; int path_name[28]; char rec_type; /* Fixed or variable records */ /* float front; */ unsigned lrsz, cisz, cinum, bytesize; /* multiplicative operands */ /* load up required parameters in arg block */ lrsz = cisz = cinum = bytesize = 0; /* front = 0; */ i = 0; while (i < 28) path_name[i++] = 0x2020; /* file name inited to blank */ path_name[28] = 0x2020; /* terminate name array */ strcpy(path_name, fname); strcat(path_name, " "); /* $GIFIL macro needs terminating blank */ psb.gipsb_lfn = 0x2020; /* blank out LFN field */ psb.gipsb_pthp = &path_name[0]; /* load pointer to pathname */ psb.gipsb_fabp = &fab; /* load ptr to file attribs */ psb.gipsb_kdp = 0x000; /* load NULL ptr, field N/A */ /* set-up arg-block for the mcl call */ adrtag.adrint = &psb; /* get char pointer to argument block */ reg.reg_b4 = adrtag.adrint; /* 'dirty' conversion of pointer */ adrtag.adrint = ®.reg_b4; /* get address of B4 register */ i = mcl($GIFIL,adrtag.adrint); if (i != 0) { printf("\n\tERRORCODE: %x\n", i); return(0); } /* end if */ rec_type = psb.gipsb_rtyp; /* if arg = 3 get lrsz for >SYSLIB2>EC to determine operating system */ if (func == 3) { lrsz_6 = fab.gfa_lrsz; if (debug) fprintf(dfp, "BU lrsz size = %d\n", lrsz_6); return(0); } lrsz = fab.gfa_lrsz; cisz = fab.gfa_cisz; /* put Fixed-relative CI size in var. */ cinum = fab.gfa_find; /* determine if a sequential file has DATA_CODE = BINARY attribute */ /* if (debug) fprintf(dfp, "\nFSIZE(): File: %s, rec_type: %c, function: %d, data_code: %x\n", fname, rec_type, func, (psb.gipsb_resv & 0x1000)); */ if ((rec_type != 'F') && (func == 1)) return(psb.gipsb_resv & 0x1000); /* recompute the CI size to exclude CI & logical record header info */ if (rec_type != 'F') /* dont try var-length SEQ files */ return(0); cisz = cisz - (((cisz / lrsz) * 4) + 8); /* compute file size in kilobytes WITHOUT using floating point ops. */ hunds = cisz/100; tens = (cisz - (hunds * 100)) / 10; units = cisz - (hunds * 100) - (tens * 10); hunds = hunds * cinum; tens = tens * cinum; units = units * cinum; bytesize = (hunds + (tens/ 10) + (units / 100)) / 10; /* front = cisz; front = front / 1024; front = front * cinum; bytesize = front; */ if (debug ) { fprintf(dfp, "\n\tThe logical record size is: %u.", lrsz); fprintf(dfp, "\n\tThe number of data bytes per CI is: %u.", cisz); fprintf(dfp, "\n\tThe highest numbered file CI is: %u.", cinum); fprintf(dfp, "\n\tThe approximate size in kilobytes is: %u.\n", bytesize); } /* end if */ return(bytesize); /* return size in bytes */ } /* end fsize */ /* * Kermit checksum routines: * * The following three routines are in keeping with 'classic' * Kermit and are presented worst to best below [FRANK DREANO] * */ /* * c h k 1 -- compute type-1 Kermit error-checking; * a 6-bit checksum. * */ chk1(pkt) char *pkt; { unsigned int chk; chk = chk2(pkt); chk = (((chk & 0300) >> 6) + chk) & 077; return(chk); } /* end of chk1 */ /* * c h k 2 -- compute the numeric sum of all bytes in the packet; * a 12-bit checksum. * */ unsigned chk2(pkt) unsigned char *pkt; { long chk; for (chk = 0; *pkt != '\0'; pkt++) chk += *pkt; return(chk & 07777); } /* end of chk2 */ /* * c h k 3 -- compute type-3 Kermit checksum; * a 16-bit cyclic redundancy check. * */ chk3(s) char *s; { unsigned int c, q; unsigned long crc = 0; while ((c = *s++) != '\0') { c &= 0177; /* strip high bit if any */ q = (crc ^ c) & 017; /* low order nibble */ crc = (crc >> 4) ^ (q * 010201); q = (crc ^ (c >> 4)) & 017; /* hi order nibble */ crc = (crc >> 4) ^ (q * 010201); } /* end while */ return(crc); } /* end chk3 */ /* * Kermit printing routines: * * help - displays command syntax specific to DHS version of Kermit * usage - print command line options showing proper syntax * printmsg - like printf with logo prepended * error - like printmsg if local Kermit; sends error packet if remote * prerrpkt - print contents of error packet received from remote * */ /* * h e l p * * The next two routines are user help displays for DHS Kermit * */ help() { printf("\nSummary of DPS-6 Superkermit:\n"); help1(); printf("\t\t\t\t hit CR for more "); timoset(30); while (timflag != 0) if (cread() != 0) break; printf("\nBasic syntax of the \"superkerm\" command is:\n"); usage(); /* exits */ } /* End of help() */ help1() { printf("This is a remote receive/send/server Kermit; normally called with\n"); printf(" command line arguments, if not, server mode is assumed.\n"); printf("CRC error checking is always requested, 7-bit ASCII transfers invoked\n"); printf(" by \"a\"-flag, otherwise 8-bit prefixed transfer is the default;\n"); printf(" mapping between LFs and CR/LF pairs is only done for ASCII transfers.\n"); printf("8-bit image mode is invoked by \"i\"-flag; there is NO Connect facility.\n"); printf("Extended packet (up to 2000 bytes) transfers are always available.\n"); printf("Incoming text files will be concatenated to via the \"c\"-flag.\n"); printf("Server mode supports many advanced server commands...see the files\n"); printf(" >SYSLIB1>SUPERKER.DOC and >SYSLIB1>SUPERKER.BWR for details.\n"); printf("If your transfer breaks down, go into connect-mode and enter\n"); printf(" ESCAPE-C, which will cause Superkermit to quit gracefully;\n"); printf(" alternatively enter ESCAPE-H, which will elicit a reassurance.\n"); printf("If debug is requested by \"-D\" flag(s) on second parameter, then\n"); printf(" debug information is written into a file whose name is \n"); printf(" the rest of the second parameter (after last \"D\"); up to three\n"); printf(" \"D\" flags may be entered (but only one \"-\"):\n"); printf("Debug = 1 gives basic trace of automaton states + error-messages,\n"); printf(" = 2 logs packets as sent/received,\n"); printf(" = 3 also logs all chars as read from line, in hex.\n"); return; } /* End of help1() */ /* * u s a g e * * Tell the user how to invoke Kermit in any mode and quit * */ usage() { cooktty(); printf ("Usage: superkerm s[abfic] [-Ddebug-file] file(s) ... (send mode)\n"); printf ("or: superkerm r[abfic] [-Ddebug-file] (receive mode)\n"); printf ("or: superkerm v[abfic] [-Ddebug-file] (server mode)\n"); printf(" where a = ASCII 7-bit file xfer (default),\n"); printf(" b = BINARY file xfer (usually DPS-6 bound-units),\n"); printf(" f = FOREIGN (MSDOS/UNIX) file xfer: *.exe, *.com, etc,\n"); printf(" i = force 8-bit binary-image xfer (no parity allowed!),\n"); printf(" c = concatenate to ASCII files if they already exist,\n\n"); printf(" Wild card xfers (all files ASCII, BINARY or FOREIGN) are legal.\n"); printf(" Under the 4.0 operating system Superkermit will work with the\n"); printf(" VIP3 Terminal Emulator configured for 7-bit 'other host' Kermit\n"); printf(" (NOT Honeywell's Kermit); it can use the ASYNCH1 AP port.\n"); printf(" debug-file is preceded by \"-\" and up to 3 \"D\"-flags.\n"); printf("or: superkerm h (help display).\n"); printf(crlf); closeall(); exit(0); } /* End of usage() */ /* * p r i n t m s g * * Print message on standard output if not remote * */ /*VARARGS1*/ printmsg(fmt, a1, a2, a3, a4, a5) char *fmt; { printf("Superkermit: "); printf(fmt,a1,a2,a3,a4,a5); printf("\n\r"); return; } /* End of printmsg() */ /* * e r r o r * * Print error message * If remote, send an error packet with the message * */ /*VARARGS1*/ error(fmt, a1, a2, a3, a4, a5) char *fmt; { char msg[100]; int len; sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */ len = strlen(msg); spack('E',n,len,msg); /* Send the error packet */ if (debug) fprintf(dfp,"%s\n",msg); return; } /* End of error() */ /* * p r e r r p k t * * Print contents of error packet received from remote Kermit * */ prerrpkt(msg) char *msg; { if (debug) { fprintf(dfp, "\nSuperkermit Aborting with following message from local Kermit:"); msg[50] = 0; fprintf(dfp,"\n \"%s\"",msg); } return; } /* End prerrpkt() */ /********************* END of FILE hd6pri.c **************************/