/* * K e r m i t File Transfer Utility * * UNIX Kermit, Columbia University, 1981, 1982, 1983 * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell * * Also: Jim Guyton, Rand Corporation * Walter Underwood, Ford Aerospace * Server Mode and Honeywell H66 & DPS8 added by * Terry Carlin, Honeywell inc. * * * For remote Kermit, format is either: * kermit r to receive files * or kermit s file ... to send files * * or kermit sv server mode * * or kermit rc receive into * working directory * * or kermit svc server mode using * working directory */ /* * Modification History: * * - Changed MYEOL character from \n to \r. * - Change char to int in bufill so getc would return -1 on * EOF instead of 255 (-1 truncated to 8 bits) * - Added read() in rpack to eat the EOL character * - Added fflush() call in printmsg to force the output * NOTE: The last three changes are not conditionally compiled * since they should work equally well on any system. * * Added support for error packets and cleaned up the printing * routines. * Added support for Honeyewll running GCOS. * Added simple server mode */ #include /* Standard UNIX definitions */ #include #include #include /* Symbol Definitions */ #define MAXPACKSIZ 94 /* Maximum packet size */ #define SOH 1 /* Start of header */ #define CR 13 /* ASCII Carriage Return */ #define SP 32 /* ASCII space */ #define DEL 127 /* Delete (rubout) */ #define ESCCHR '^' /* Default escape character for CONNECT */ #define MAXTRY 10 /* Times to retry a packet */ #define MYQUOTE '#' /* Quote character I will use */ #define MYPAD 0 /* Number of padding characters I will need */ #define MYPCHAR 0 /* Padding character I need (NULL) */ #define MYEOL '\r' /* End-Of-Line character for UTS systems */ #define MYTIME 10 /* Seconds after which I should be timed out */ #define MAXTIM 60 /* Maximum timeout interval */ #define MINTIM 2 /* Minumum timeout interval */ #define TRUE -1 /* Boolean constants */ #define FALSE 0 /* Macro Definitions */ /* * tochar: converts a control character to a printable one by adding a space. * * unchar: undoes tochar. * * ctl: converts between control characters and printable characters by * toggling the control bit (ie. ^A becomes A and A becomes ^A). */ #define tochar(ch) ((ch) + ' ') #define unchar(ch) ((ch) - ' ') #define ctl(ch) ((ch) ^ 64 ) /* Global Variables */ int size, /* Size of present data */ tmpfil, /* User wanted temp file for output */ cflg, /* cwd flag */ rpsiz, /* Maximum receive packet size */ spsiz, /* Maximum send packet size */ pad, /* How much padding to send */ timint, /* Timeout for foreign host on sends */ n, /* Packet number */ numtry, /* Times this packet retried */ oldtry, /* Times previous packet retried */ ttyfd, /* File descriptor of tty for I/O, 0 if remote */ remote, /* -1 means we're a remote kermit */ image, /* -1 means 8-bit mode */ debug, /* indicates level of debugging output (0=none) */ cnvfilnam, /* -1 means do file name case conversions */ filecount, /* Number of files left to send */ state, /* Present state of the automaton */ padchar, /* Padding character to send */ eol, /* End-Of-Line character to send */ escchr, /* Connect command escape character */ quote; /* Quote character in incoming data */ char **filelist, /* List of files to be sent */ *filnam, /* Current file name */ recpkt[MAXPACKSIZ], /* Receive packet buffer */ packet[MAXPACKSIZ]; /* Packet buffer */ char working_directory[40] = "/"; FILE *fp, /* File pointer for current disk file */ *fddebug, /* File for debugging output */ *log; /* File pointer for Logfile */ /* * m a i n * * Main routine - parse command and options, set up the * tty lines, and dispatch to the appropriate routine. */ main(argc,argv) int argc; /* Character pointers to and count of */ char **argv; /* command line arguments */ { char *ttyname, /* tty name for LINE argument */ *cp; /* char pointer */ char savefile[60]; /* work area for filename and cwd */ int rflg, sflg; /* flags for RECEIVE, SEND */ int svflg; /* server mode */ int cmd; /* for parser */ extern int dobreak(); /* just need its address */ if (argc < 2) usage(); /* Make sure there's a command line */ cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */ printf("Kermit-GCOS V3.0\n"); /* Initialize these values and hope the first packet will get across OK */ eol = CR; /* EOL for outgoing packets */ quote = '#'; /* Standard control-quote char "#" */ pad = 0; /* No padding */ padchar = NULL; /* Use null if any padding wanted */ cflg = 0; sflg = rflg = svflg = 0; /* Turn off all parse flags */ ttyname = 0; /* Default is remote mode */ tmpfil = FALSE; /* Create perm files as default */ image = FALSE; /* translation and filename case */ cnvfilnam = TRUE; /* conversion for UNIX systems */ while ((*cp) != NULL) /* Parse characters in first */ { cmd = *cp++; if (isupper(cmd)) cmd = tolower(cmd); switch (cmd) { case 's': /* S = Send command */ sflg++; break; case 'r': /* R = Receive command */ rflg++; break; case 'v': /* server mode */ if (sflg) { sflg = 0; svflg++; } else printf("Unknown mode\n"); break; case 'c': /* Change working directory */ printf("cwd: Enter working directory "); gets(working_directory); strcat(working_directory, "/"); cflg++; break; case 'd': /* D = Increment debug mode count */ if (!debug) if ((fddebug = fopen("kermit.d", "w")) == NULL) { printf("Could not open kermit.d\n"); exit(1); } debug++; break; case 'f': cnvfilnam = FALSE; /* F = don't do case conversion */ break; /* on filenames */ case 't': /* wants uploaded file to be temp */ tmpfil++; working_directory[0] = '\0'; /* null out string */ break; } } /* Done parsing */ if ((sflg+rflg+svflg) != 1) /* Only one command allowed */ usage(); if ((tmpfil + cflg) > 1) { printf("Can't have working directory and temporary files\n"); exit(); } ttyfd = 0; /* communications line */ remote = TRUE; /* Put the proper tty into the correct mode */ system("LINE 160"); /* change line length to 160 chars */ /* Set up tty break vectors */ signal( _SIGBRK, dobreak); /* All set up, now execute the command that was given. */ if (debug) { dbprint("Debugging level = %d\n\n",debug); if (sflg) dbprint("Send command\n\n"); if (rflg) dbprint("Receive command\n\n"); if (svflg) dbprint("Server mode\n"); } if (svflg) servsw(); if (sflg) /* Send command */ { if (argc--) filnam = *argv++; /* Get file to send */ else { usage(); /* and give error */ } if (cflg) /* see if working directory set */ { strcpy(savefile, working_directory); strcat(savefile, filnam); filnam = savefile; } fp = NULL; /* Indicate no file open yet */ filelist = argv; /* Set up the rest of the file list */ filecount = argc; /* Number of files left to send */ state = 'S'; /* Set up initial state */ printf("Sending file\n"); if (sendsw(sflg) == FALSE) /* Send the file(s) */ printmsg("Send failed."); /* Report failure */ else /* or */ printmsg("done."); /* success */ } if (rflg) /* Receive command */ { state = 'R'; /* Set up initial state */ printf("Ready to receive file\n"); if (recsw() == FALSE) /* Receive the file(s) */ printmsg("Receive failed."); else /* Report failure */ printmsg("done."); /* or success */ } if (debug) fclose(fddebug); } /* * Servsw is the state table switcher for Server mode. It will call * sendsw() and recsw() to to the real work. */ servsw() { int num, len, i; int pkttype; /* packet type */ char savename[60], *cptr; printf("Server mode\n"); while(TRUE) { n = numtry = 0; switch((pkttype = rpack(&len, &num, recpkt))) { case 'I': /* Info packet */ rpar(recpkt); spar(packet); spack('Y',n,6,packet); break; case 'S': rpar(recpkt); spar(packet); spack('Y',n,6,packet); n = (n + 1) % 64; state = 'F'; recsw(); /* go do the file receive */ break; case 'R': if (cflg) /* do cwd if there */ { strcpy(savename,working_directory); strcat(savename, recpkt); } else strcpy(savename, recpkt); /* save away filename */ filnam = savename; fp = NULL; filecount = 0; state = 'S'; /* do send now */ sendsw(FALSE); /* send the file they want */ break; case 'G': /* Generic Kermit command */ switch(recpkt[0]) /* Command is in first char */ { case 'L': /* logoff kermit and system */ spack('Y',n,0,0); if (debug) fclose(fddebug); system("LOGOFF"); /* logoff */ break; /* never get here but ??? */ case 'F': /* finish kermit return to tss */ spack('Y',n,0,0); return(TRUE); case 'C': /* Change working directory */ spack('Y',n,0,0); len = unchar(recpkt[1]); cptr = working_directory; for (i=2;len;i++,len--) *cptr++ = recpkt[i]; *cptr++ = '/'; *cptr = '\0'; break; default: error("Unemplemented Generic kermit command"); break; } break; case 'N': /* NAK, ignore */ break; default: if (debug) dbprint("Unknown packet type %c\n", pkttype); error("Unknown packet type"); } } } /* * s e n d s w * * Sendsw is the state table switcher for sending files. It loops until * either it finishes, or an error is encountered. The routines called * by sendsw are responsible for changing the state. * */ sendsw(sflg) int sflg; /* need to know if comming in from send or serv */ { if (sflg) /* if in send mode then */ sleep(10); /* give user a chance to start receive */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ while(TRUE) /* Do this as long as necessary */ { if (debug) dbprint("sendsw state: %c\n",state); switch(state) { case 'S': state = sinit(); break; /* Send-Init */ case 'F': state = sfile(); break; /* Send-File */ 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': return (TRUE); /* Complete */ case 'A': return (FALSE); /* "Abort" */ default: return (FALSE); /* Unknown, fail */ } } } /* * s i n i t * * Send Initiate: send this host's parameters and get other side's back. */ sinit() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spar(packet); /* Fill up init info packet */ spack('S',n,6,packet); /* Send an S packet */ switch(rpack(&len,&num,recpkt)) /* What was the reply? */ { case 'N': return(state); /* NAK, try it again */ case 'Y': /* ACK */ if (n != num) /* If wrong ACK, stay in S state */ return(state); /* and try again */ rpar(recpkt); /* Get other side's init info */ if (eol == 0) eol = '\n'; /* Check and set defaults */ if (quote == 0) quote = '#'; numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ return('F'); /* OK, switch state to F */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, try again */ default: return('A'); /* Anything else, just "abort" */ } } /* * s f i l e * * Send File Header. */ sfile() { int num, len; /* Packet number, length */ char filnam1[50], /* Converted file name */ *newfilnam, /* Pointer to file name to send */ *cp; /* char pointer */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ if (fp == NULL) /* If not already open, */ { if (debug) dbprint(" Opening %s for sending.\n",filnam); fp = fopen(filnam,"r"); /* open the file to be sent */ if (fp == NULL) /* If bad file pointer, give up */ { error("Cannot open file %s",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 (cnvfilnam) /* 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 */ printmsg("Sending %s as %s",filnam,newfilnam); 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 */ 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, stay in F state */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ size = bufill(packet); /* Get first data from file */ return('D'); /* Switch state to D */ 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: return('A'); /* Something else, just "abort" */ } } /* * s d a t a * * Send File Data */ sdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */ spack('D',n,size,packet); /* Send a D 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, fail */ numtry = 0; /* Reset try counter */ n = (n+1)%64; /* Bump packet count */ if ((size = bufill(packet)) == EOF) /* Get data from file */ return('Z'); /* If EOF set state to that */ return('D'); /* Got data, stay in state D */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: return(state); /* Receive failure, stay in D */ default: return('A'); /* Anything else, "abort" */ } } /* * s e o f * * Send End-Of-File. */ 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) dbprint(" Closing input file %s, ",filnam); fclose(fp); /* Close the input file */ fp = NULL; /* Set flag indicating no file open */ if (debug) dbprint("looking for next file...\n"); if (gnxtfl() == FALSE) /* No more files go? */ return('B'); /* if not, break, EOT, all done */ if (debug) dbprint(" New file is %s\n",filnam); 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: return('A'); /* Something else, "abort" */ } } /* * s b r e a k * * Send Break (EOT) */ 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(state); /* Receive failure, stay in B */ default: return ('A'); /* Other, "abort" */ } } /* * r e c s w * * This is the state table switcher for receiving files. */ recsw() { if (state == 'R') n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ while(TRUE) { if (debug) dbprint(" recsw state: %c\n",state); switch(state) /* Do until done */ { case 'R': state = rinit(); break; /* Receive-Init */ case 'F': state = rfile(); break; /* Receive-File */ case 'D': state = rdata(); break; /* Receive-Data */ case 'C': return(TRUE); /* Complete state */ case 'A': return(FALSE); /* "Abort" state */ } } } /* * r i n i t * * Receive Initialization */ rinit() { int len, num; /* Packet length, number */ if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */ switch(rpack(&len,&num,packet)) /* Get a packet */ { case 'S': /* Send-Init */ rpar(packet); /* Get the other side's init data */ spar(packet); /* Fill up packet with my init info */ spack('Y',n,6,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 */ return('F'); /* Enter File-Receive state */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Didn't get packet */ spack('N',n,0,0); /* Return a NAK */ return(state); /* Keep trying */ default: return('A'); /* Some other packet type, "abort" */ } } /* * r f i l e * * Receive File Header */ 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? */ { /* Yes, ACK it again with */ spar(packet); /* our Send-Init parameters */ spack('Y',num,6,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,0); 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 */ if (!tmpfil) /* fix up to make quick access perm file*/ { strcpy(filnam1, working_directory); } else filnam1[0] = '\0'; strcat(filnam1, packet); /* Copy the file name */ if (!tmpfil) /* file names can only be 8 chars */ filnam1[(strlen(working_directory) + 8)] = '\0'; else filnam1[8] = '\0'; if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */ { error("Cannot create %s",filnam1); /* Give up if can't */ return('A'); } else /* OK, give message */ printmsg("Receiving %s as %s",packet,filnam1); spack('Y',n,0,0); /* 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,0); /* Say OK */ return('C'); /* Go to complete state */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Didn't get packet */ spack('N',n,0,0); /* Return a NAK */ return(state); /* Keep trying */ default: return ('A'); /* Some other packet, "abort" */ } } /* * r d a t a * * Receive Data */ rdata() { int num, len; /* Packet number, length */ if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */ switch(rpack(&len,&num,packet)) /* 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,6,packet); /* 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 */ bufemp(packet,len); /* Write the data to the file */ spack('Y',n,0,0); /* Acknowledge the packet */ oldtry = numtry; /* Reset the try counters */ numtry = 0; /* ... */ n = (n+1)%64; /* Bump packet number, mod 64 */ 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(fp); /* Close the file */ n = (n+1)%64; /* Bump packet number */ return('F'); /* Go back to Receive File state */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('A'); /* abort */ case FALSE: /* Didn't get packet */ spack('N',n,0,0); /* Return a NAK */ return(state); /* Keep trying */ default: return('A'); /* Some other packet, "abort" */ } } /* * KERMIT utilities. */ /* * s p a c k * * Send a Packet */ spack(type,num,len,data) char *data; int num, len, type; { int i,chksum; /* Character loop counter */ char buffer[100]; /* Checksum, packet buffer */ register char *bufp; /* Buffer pointer */ if (debug>1) /* Display outgoing packet */ { if (data != NULL) data[len] = '\0'; /* Null-terminate data to print it */ dbprint(" spack type: %c\n",type); dbprint(" num: %d\n",num); dbprint(" len: %d\n",len); if (data != NULL) dbprint(" data: \"%s\"\n",data); } bufp = buffer; /* Set up buffer pointer */ for (i=1; i<=pad; i++) putchar(padchar); /* Issue any padding */ *bufp++ = SOH; /* Packet marker, ASCII 1 (SOH) */ *bufp++ = tochar(len+3); /* Send the character count */ chksum = tochar(len+3); /* Initialize the checksum */ *bufp++ = tochar(num); /* Packet number */ chksum += tochar(num); /* Update checksum */ *bufp++ = type; /* Packet type */ chksum += type; /* Update checksum */ for (i=0; i> 6)+chksum)&077; /* Compute final checksum */ *bufp++ = tochar(chksum); /* Put it in the packet */ *bufp++ = eol; /* Extra-packet line terminator */ *bufp = '\0'; /* make it a string */ write(1, buffer, bufp-buffer+1); /* Send the packet */ } /* * r p a c k * * Read a Packet */ rpack(len,num,data) int *len, *num; /* Packet length, number */ char *data; /* Packet data */ { int i, done; /* Data character number, loop exit */ char t, /* Current input character */ type, /* Packet type */ cchksum, /* Our (computed) checksum */ rchksum; /* Checksum received from other host */ while (t != SOH) /* Wait for packet header */ { t = getchar(); t &= 0177; /* Handle parity */ } done = FALSE; /* Got SOH, init loop */ while (!done) /* Loop to get a packet */ { t = getchar(); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum = t; /* Start the checksum */ *len = unchar(t)-3; /* Character count */ t = getchar(); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum = cchksum + t; /* Update checksum */ *num = unchar(t); /* Packet number */ t = getchar(); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum = cchksum + t; /* Update checksum */ type = t; /* Packet type */ for (i=0; i<*len; i++) /* The data itself, if any */ { /* Loop for character count */ t = getchar(); /* Get character */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynch if SOH */ cchksum = cchksum + t; /* Update checksum */ data[i] = t; /* Put it in the data buffer */ } data[*len] = 0; /* Mark the end of the data */ t = getchar(); /* Get last character (checksum) */ rchksum = unchar(t); /* Convert to numeric */ t = getchar(); /* get EOL character and toss it */ if (!image) t &= 0177; /* Handle parity */ if (t == SOH) continue; /* Resynchronize if SOH */ done = TRUE; /* Got checksum, done */ } if (debug>1) /* Display incoming packet */ { if (data != NULL) data[*len] = '\0'; /* Null-terminate data to print it */ dbprint(" rpack type: %c\n",type); dbprint(" num: %d\n",*num); dbprint(" len: %d\n",*len); if (data != NULL) dbprint(" data: \"%s\"\n",data); } /* Fold in bits 7,8 to compute */ cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */ if (cchksum != rchksum) return(FALSE); return(type); /* All OK, return packet type */ } /* * b u f i l l * * Get a bufferful of data from the file that's being sent. * Only control-quoting is done; 8-bit & repeat count prefixes are * not handled. */ bufill(buffer) char buffer[]; /* Buffer */ { int i, /* Loop index */ t; /* Char read from file */ char t7; /* 7-bit version of above */ i = 0; /* Init data buffer pointer */ while((t = getc(fp)) != EOF) /* Get the next character */ { t7 = t & 0177; /* Get low order 7 bits */ if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */ { /* special handling? */ if (t=='\n' && !image) { /* Do LF->CRLF mapping if !image */ buffer[i++] = quote; buffer[i++] = ctl('\r'); } buffer[i++] = quote; /* Quote the character */ if (t7 != quote) { t = ctl(t); /* and uncontrolify */ t7 = ctl(t7); } } if (image) buffer[i++] = t; /* Deposit the character itself */ else buffer[i++] = t7; if (i >= spsiz-8) return(i); /* Check length */ } if (i==0) return(EOF); /* Wind up here only on EOF */ return(i); /* Handle partial buffer */ } /* * b u f e m p * * Put data from an incoming packet into a file. */ bufemp(buffer,len) char buffer[]; /* Buffer */ int len; /* Length */ { int i; /* Counter */ char t; /* Character holder */ for (i=0; i