/* pe7ptb.c */ /* include external declarations */ #include "pe7inc.h" /* * g n x t f l * * Get next file in a file group * */ gnxtfl() { if (filecount-- == 0) return (FALSE); /* If no more, fail */ if (debug) printf("Gnxtfl 1: filelist = \"%s\"\n",*filelist); filnam = *(filelist++); return (TRUE); } /* * d o s t a t s * * Gather various statistics * */ dostat(type) int type; { ULONG time(); switch(type) { case 1: /* Init Overall totals */ total.files = 0; total.fc = 0; total.pli = 0; total.plo = 0; total.cli = 0; total.clo = 0; total.time = 0; break; case 2: /* Init File totals */ file.fc = 0; file.pli = 0; file.plo = 0; file.cli = 0; file.clo = 0; file.time = time(); break; case 3: /* Accumulate Overall totals */ file.time = time()-file.time; if (vflg) { printf("%d Bytes %d Seconds %d/%d Packets", file.fc, file.time, file.plo, file.pli); printf(" %d/%d Characters\n", file.clo, file.cli); } total.fc += file.fc; total.pli += file.pli; total.plo += file.plo; total.cli += file.cli; total.clo += file.clo; total.time += file.time; break; case 4: /* Count total files */ total.files++; } } /* * d o p a r * * Set parity bit * */ dopar(ch) TEXT ch; { TEXT a; a=ch; if (pflg) /* True = generate parity */ { a &= 0177; /* Strip top bit */ switch (pflg) { case 'o': /* Odd parity */ a |= 0200; /* Set bit then do even */ case 'e': /* Even parity */ a = (a & 15) ^ ((a >> 4) & 15); a = (a & 3) ^ ((a >> 2) & 3); a = (a & 1) ^ ((a >> 1) & 1); a = ch & 0177 | (a << 7); case 's': /* Space parity */ default: /* No parity */ break; case 'm': /* Mark parity */ a |= 0200; } } return (a); } /* * c h k c h a r * * Check range of input and return the character or FALSE * */ TEXT chkchar(c) TEXT c; { return ((c < 33) || (c > 62 && c < 96) || (c > 126) ? FALSE : c); } /* * f l u s h i n p u t * * Dump all pending input to clear stacked up NACK's. * (Implemented only for Berkeley Unix at this time). * */ flushinput() /* Null version for non-Berkeley Unix */ { estty(ttyfd,&ttymode); /* This flushes the input buffer */ } /* * Kermit printing routines: * * printmsg - like printf with "Kermit: " prepended * error - like printmsg if local kermit; sends a error packet if remote * prerrpkt - print contents of error packet received from remote host */ /* * U s a g e * * Like printmsg but will exit after printing the message * */ Usage(message,a1,a2,a3,a4,a5) TEXT *message; { TEXT cp[BUFSIZE]; cpystr(&cp, "Kermit usage: ", message, "\n", NULL); printf(&cp, a1, a2, a3, a4, a5); if (ttyfd > 0) estty (ttyfd,&savemode); /* Restore the tty to what it was */ exit(NO); } /* * p r i n t m s g * * Print message on standard output if not remote. * */ printmsg(fmt, a1, a2, a3, a4, a5) TEXT *fmt; { TEXT cp[BUFSIZE]; cpystr(&cp, "Kermit: ", fmt, "\n", NULL); printf(&cp, a1, a2, a3, a4, a5); } /* * e r r o r * * Print error message. * * If remote, send an error packet with the message. * */ error(fmt, a1, a2, a3, a4, a5) TEXT *fmt; { TEXT cp[MAXPACKSIZ], msg[80]; /* Some arrays for the strings */ int len; /* The length of these arrays */ convert(&cp, fmt); /* Convert the format string */ len = decode(msg, 80, &cp, a1, a2, a3, a4, a5); spack('E',n,len,msg); /* Send the error packet */ return; } /* * c o n v e r t * * Convert the UNIX format string to an IDRIS format string * */ convert(out, in) TEXT *out, *in; { TEXT t, *cpp; cpp = out; /* Init the buffer pointer */ while ((t = *cpp++ = *in++) != NULL) if (t == '%') switch (t = *in++) { case 'c': *cpp++ = 'a'; *cpp++ = 'c'; break; case 'x': *cpp++ = 'h'; case 'd': *cpp++ = 'i'; break; case 's': *cpp++ = 'p'; break; case '\0': --in; break; default: *cpp++ = t; } } /* * p r e r r p k t * * Print contents of error packet received from remote host. * */ prerrpkt(msg) TEXT *msg; { putstr(STDERR,\ "Kermit: Abort with error from remote host:\n",\ " ",msg,"\n",NULL); return; } /* * p r i n t f * * Print formatted output. Convert from UNIX to IDRIS * */ printf(msg, a1, a2, a3, a4, a5) TEXT *msg; { TEXT cp[MAXPACKSIZ]; /* Line pointer for the reformatted string */ convert(&cp, msg); /* Convert the string */ putfmt(&cp, a1, a2, a3, a4, a5); } /* * i n l i n e * * Input a line (up to break char) from communications line * */ inline(data) TEXT *data; { TEXT t; int len, t1; t1 = tflg ? XON : MYEOL; len = 0; do { if (ioread(&t) <= 0) { data[len]=MYEOL; return(len); } else if (t) { if (t == SOH) /* Resync on SOH */ len = 0; else data[len++] = t; } } while ((t != t1) && (len < MAXPACKSIZ)); file.cli += len + 1; data[len] = '\0'; /* Terminate input string */ if (tflg) /* Turn around flag on? */ do if (ioread(&t) < 0) break; while (t != XON); return (len); } /* * i o r e a d * * Read a character from the i/o channel * */ ioread(t) TEXT *t; { ULONG time_end, time(); int result; if (timint > 0) { time_end = time() + timint; do if ((result = read(ttyfd, t, 1)) > 0) break; while (time_end >= time()); } else result = read(ttyfd, t, 1); if (pflg) *t &= 0177; /* Handle parity */ return (result); } /* * x f i l e * * Fetch file and send file header * */ TEXT xfile() { TEXT filnam1[MAXFNAME]; /* A buffer for the file name */ TEXT *newfilnam; /* A pointer into the filename */ TEXT *cp; /* char pointer */ int num, len; /* Packet number, length */ ULONG time(); if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */ if (fd == NULL) /* If not already open, */ { /* cpystr(filnam1, filnam, NULL); /* */ btobemp(filnam1, filnam, MAXFNAME); if (filnamcnv) /* Convert upper case to lower */ for (cp = &filnam1; *cp != '\0'; cp++) *cp = tolower(*cp); newfilnam = cp = filnam; while (*cp != '\0') /* Strip leading directories */ if (*cp++ == '/') newfilnam = cp; len = cp - newfilnam; /* Compute length of filename */ if (debug) printf("Xfile 1: Opening %s for sending.\n",&filnam1); /* Open file to be sent */ if ((fd = fopen(&pfio, filnam1, READ)) == NULL) { /* If bad file pointer, give up */ error("Cannot open file %s",filnam); return ('C'); /* Go back to idle mode */ } if (vflg) printmsg("Sending %s as %s", filnam1, newfilnam); } dostat(2); spack('F',n,len,newfilnam); /* Send an F 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 */ case 'Y': if (n != num) /* which is just like an ACK for */ { /* Wrong packet number */ case FALSE: /* Receive failure, stay in F state */ nxi++; return (state); } nxtpkt(); dostat(4); repeat_count = 0; /* Reset repeat character counter */ empty[1-pknum] = 0; /* Make other buffer empty */ if ((empty[pknum] = size[pknum] = bufill (packet[pknum])) != EOF) return ('E'); /* Switch to data state */ return ('Z'); /* Must be end of file */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Something else, just "abort" */ } } /* * s d a t a * * Send File Data * */ TEXT sdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */ /* If the packet has not been acked then do not fill it We may need to retransmit it again */ spack('D',n,size[pknum],packet[pknum]); /* Send a D packet */ if (!empty[1-pknum]) empty[1-pknum] = size[1-pknum] = bufill(packet[1-pknum]); 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': if (n != num) /* which is just like an ACK for */ { /* Wrong packet number */ case FALSE: /* Receive failure, stay in D */ nxi++; return (state); } empty[pknum] = 0; /* Empty this buffer */ nxtpkt(); if (size[pknum] == EOF) return ('Z'); /* Send eof packet */ return ('E'); /* Got data, stay in state E */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Anything else, "abort" */ } } /* * r d a t a * * Receive Data * */ TEXT rdata() { int num, len; /* Packet number, length */ ULONG time(); if (numtry++ > MAXTRY) return ('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,recpkt)) /* Get packet */ { 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)) /* Else check packet number */ { /* Previous packet again? */ spack('Y',num,0,0); /* 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 */ spack('Y',n,0,0); /* Acknowledge the packet */ bufemp(recpkt,len); /* Write the data to the file */ oldtry = numtry; /* Reset the try counters */ nxtpkt(); 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,0);/* 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,0); /* OK, ACK it. */ fclose(&pfio); /* Close the file */ fd = NULL; /* Say the file is closed */ nxtpkt(); dostat(3); return ('F'); /* Go back to Receive File state */ case FALSE: /* Didn't get packet */ nxi++; spack('N',n,0,0); /* Return a NAK */ return (state); /* Keep trying */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Some other packet, "abort" */ } } /* * s e o f * * Send End-Of-File. * */ TEXT seof() { int num, len; /* Packet number, length */ ULONG time(); if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */ spack('Z',n,0,0); /* 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, */ case 'Y': if (n != num) /* which is just like an ACK for */ { /* Wrong packet number */ case FALSE: /* Receive failure, stay in Z */ nxi++; return (state); } nxtpkt(); dostat(3); if (debug) printf("Seof 1: Closing input file %s\n",filnam); fclose(&pfio); /* Close the file */ fd = NULL; /* Set flag indicating no file open */ if (debug) printf("Seof 2: Looking for next file...\n"); if (gnxtfl() == FALSE) /* No more files go? */ return ('B'); /* if not, break, EOT, all done */ if (debug) printf("Seof 3: New file is %s\n",filnam); return ('T'); /* More files, switch state to T */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Something else, "abort" */ } } /* * s b r e a k * * Send Break (EOT) * */ TEXT sbreak() { int num, len; /* Packet number, length */ ULONG time(); 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': if (n != num) /* Which is just like an ACK for */ { /* Wrong packet number */ case FALSE: /* Receive failure, stay in B */ nxi++; return (state); } nxtpkt(); return ('C'); /* Switch state to Complete */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Other, "abort" */ } } /* * s f i n i s h * * Send Finish (LOGOUT) * */ TEXT sfinish() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return ('A'); /* If too many tries "abort" */ spack('G',n,1,"F"); /* Send a GF 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': if (n != num) /* which is just like an ACK for */ { /* Wrong packet number */ case FALSE: /* Receive failure, stay in B */ nxi++; return (state); } nxtpkt(); return ('C'); /* Switch state to Complete */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ default: return ('A'); /* Other, "abort" */ } } /* * KERMIT utilities. * */ /* * s p a c k * * Send a Packet * */ spack(type,num,len,data) TEXT type, *data; int num, len; { register int i; /* Character loop counter */ register TEXT *bufp; /* Buffer pointer */ TEXT buffer[100]; /* Packet buffer */ TEXT temp[12]; /* A buffer for a status message */ int checksum; data[len] = '\0'; /* Null-terminate data to print it */ if (debug>1) /* Display outgoing packet */ { printf("Spack 1: type: %c\n",type); printf(" num: %d\n",num); printf(" len: %d\n",len); if (len != 0) printf(" data: \"%s\"\n",data); } bufp = buffer; /* Set up buffer pointer */ for (i=1; i<=pad; i++) write(ttyfd,&padchar,1); /* Issue any padding */ *bufp++ = dopar(SOH); /* Packet marker, ASCII 1 (SOH) */ /* Send character count and set up checksum */ *bufp++ = dopar(tochar(len + chkt - '0' + 2)); *bufp++ = dopar(tochar(num)); /* Packet number */ *bufp++ = dopar(type); /* Packet type */ for (i=0; i> 6)); *bufp++ = dopar(tochar(checksum & 077)); break; case '3': checksum = chk3(buffer+1); *bufp++ = dopar(tochar((checksum & 0170000) >> 12)); *bufp++ = dopar(tochar((checksum & 07700) >> 6)); *bufp++ = dopar(tochar(checksum & 077)); break; } if (eol) *bufp++ = dopar(eol); /* Extra-packet line terminator */ *bufp = '\0'; i = bufp - buffer; write(ttyfd, buffer, i); /* Send the packet */ file.plo++; file.clo += i; if (vflg) { if (nxi == nxs) write(STDERR,&temp,decode(&temp,12,"%5i/\r",nxo++)); else write(STDERR,&temp,decode(&temp,12,"%5i/%5i\r", nxo++, nxs = nxi)); } } /* * r p a c k * * Read a Packet * */ rpack(len,num,data) int *len, *num; /* Packet length, number */ TEXT *data; /* Packet data */ { int chksum, i, j, len1, pbl; TEXT t, /* Current input character */ type, /* Packet type */ cchksum[4], /* Our (computed) checksum */ rchksum[4], /* Checksum received from other host */ rpacket[MAXPACKSIZ]; /* Receive packet */ if(!(len1=inline(&rpacket))) return (FALSE); i = 0; if ((t = rpacket[i++]) == MYEOL) return (FALSE); *len = unchar(t); /* Character count */ if ((t = rpacket[i++]) == MYEOL) return (FALSE); *num = unchar(t); /* Packet number */ if ((type = rpacket[i++]) == MYEOL) return (FALSE); pbl = ((type == 'S') || (type == 'I')) ? 1 : type == 'N' ? *len - 2 : chkt - '0'; *len -= pbl + 2; /* Data length */ for (j=0; j < *len;) /* The data itself, if any */ if ((data[j++] = rpacket[i++]) == MYEOL) return (FALSE); data[*len] = '\0'; /* Mark the end of the data */ /* Fetch the checksum */ cchksum[0] = '\0'; cchksum[1] = '\0'; cchksum[2] = '\0'; cchksum[3] = '\0'; rchksum[0] = '\0'; rchksum[1] = '\0'; rchksum[2] = '\0'; rchksum[3] = '\0'; for (j=0; j < pbl;) /* The checksum */ { if ((rchksum[j++] = rpacket[i]) == MYEOL) return (FALSE); rpacket[i++] = '\0'; } if (debug > 1) /* Display incoming packet */ { printf("Rpack 2: type: %c\n",type); printf(" num: %d\n",*num); printf(" len: %d\n",*len); if (*len != 0) printf(" data: \"%s\"\n",data); } switch (pbl) { case 1: cchksum[0] = tochar(chk1(&rpacket)); break; case 2: chksum = chk2(&rpacket); cchksum[0] = tochar((chksum & 07700) >> 6); cchksum[1] = tochar(chksum & 077); break; case 3: chksum = chk3(&rpacket); cchksum[0] = tochar((chksum & 0170000) >> 12); cchksum[1] = tochar((chksum & 07700) >> 6); cchksum[2] = tochar(chksum & 077); } if (!cmpstr(cchksum, rchksum)) type = FALSE; file.pli++; flushinput(); return (type); /* All OK, return packet type */ } /* * n e x t p k * * Increment packet number to the next one. Reset retry counter. * */ nxtpkt() { pknum = 1 & (n = (n+1)%64); /* Bump packet count */ numtry = 0; /* Start a new counter */ } /* pe7ptb.c End-of-file */