/* * K e r m i t File Transfer Utility * */ #include /* Symbol Definitions */ #define MAXPACKSIZ 94 /* Maximum packet size */ #define MYPACKSIZ 94 /* My 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 DEFPAR '\0' /* Default no parity */ #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 (0) */ #define DEFMAXL 80 /* Default packer size */ #define DEFTIME 5 /* Default timeout */ #define DEFPAD 0 /* Default pad characters */ #define DEFPADC 0 /* Default pad character */ #define DEFEOL '\r' /* Default EOL character */ #define DEFQUOTE '#' /* Default QUOTE character */ #define DEFQBIN 'N' /* Default QBIN character */ #define QBIN '&' /* Character for binary quoting */ #define MYEOL '\n' /* End-Of-Line character I need */ #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 */ char version[]="Uman Kermit. Version 0.02\n"; int size, /* Size of present data */ 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 */ parity, /* o,e,s,m or 0 */ debug, /* indicates level of debugging output (0=none) */ qflag, /* -1 if doing 8 bit quoting */ filecount; /* Number of files left to send */ char 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 */ qbin, /* character for binary quoting */ **filelist, /* List of files to be sent */ *filnam, /* Current file name */ recpkt[MAXPACKSIZ], /* Receive packet buffer */ packet[MAXPACKSIZ]; /* Packet buffer */ FILE *fp,*fopen(); /* File pointer for current disk file */ FILE *fopenb(),*(*kfopen)(); /* jgc dec 25th 1985 */ /* * 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 *cp; /* char pointer */ int cflg, rflg, sflg; /* flags for CONNECT, RECEIVE, SEND */ printf("%s",version); /* Print out the version number */ if (argc < 2) usage(); /* Make sure there's a command line */ cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */ /* Initialize these values */ /* Hope the first packet will get across OK */ eol = CR; /* EOL for outgoing packets */ quote = '#'; /* Standard control-quote char "#" */ pad = 0; /* No padding */ padchar = '\0'; /* Use null if any padding wanted */ timint = DEFTIME ; /* Default timeout */ cflg = sflg = rflg = 0; /* Turn off all parse flags */ /* qflag = FALSE; */ en8quote(FALSE); /* jgc dec 25th. 1985 */ /* and not 8 bit quoting */ escchr = ESCCHR; /* Default escape character */ parity = DEFPAR; /* Default to no parity */ while ((*cp) != NULLPTR) /* Parse characters in first arg. */ switch (*cp++) { case 'c': /* C = Connect command */ cflg++; break; case 's': /* S = Send command */ sflg++; break; case 'r': /* R = Receive command */ rflg++; break; case 'd': /* D = Increment debug mode count */ debug++; break; case 'p': /* P = Set parity */ parity = *cp++; if ((parity=='n')||(parity=='N')) parity='\0'; if (!parity) break; /* jgc dec 25th. 1985 */ case 'q': /* q = Do 8 bit quoting */ /* qflag = TRUE; */ en8quote(TRUE); /* jgc dec 25th. 1985 */ break; } /* Done parsing */ if ((cflg+sflg+rflg) != 1) usage(); /* Only one command allowed */ /* All set up, now execute the command that was given. */ if (debug) { printf("Debugging level = %d\n\n",debug); if (cflg) printf("Connect command\n\n"); if (sflg) printf("Send command\n\n"); if (rflg) printf("Receive command\n\n"); } if (cflg) connect(); /* Connect command */ if (sflg) /* Send command */ { if (argc--) filnam = *argv++; /* Get file to send */ else { usage(); } fp = NULLPTR; /* Indicate no file open yet */ filelist = argv; /* Set up the rest of the file list */ filecount = argc; /* Number of files left to send */ if (sendsw() == FALSE) /* Send the file(s) */ printmsg("Send failed."); /* Report failure */ else /* or */ printmsg("done."); /* success */ } if (rflg) /* Receive command */ { if (recsw() == FALSE) /* Receive the file(s) */ printmsg("Receive failed."); else /* Report failure */ printmsg("done."); /* or success */ } /* Restore controlling tty's modes */ } /* * 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() { char sinit(), sfile(), sdata(), seof(), sbreak(); state = 'S'; /* Send initiate is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ while(TRUE) /* Do this as long as necessary */ { if (debug) printf("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. */ char sinit() { int num, len; /* Packet number, length */ /* If too many tries, give up */ if (numtry++ > MAXTRY) return('A'); len = spar(packet); /* Fill up init info packet */ flushinput(); /* Flush pending input */ spack('S',n,len,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,len); /* Get other side's init info */ 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. */ char sfile() { int num, len; /* Packet number, length */ char filnam1[50], /* Converted file name */ *newfilnam, /* Pointer to file name to send */ *cp; /* char pointer */ /* If too many tries, give up */ if (numtry++ > MAXTRY) return('A'); if (fp == NULLPTR) /* If not already open, */ { if (debug) printf("\tOpening %s for sending.\n",filnam); fp = (*kfopen)(filnam,"r"); /* open the file to be sent */ if (fp == NULLPTR) /* 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; for (cp = newfilnam; *cp != '\0'; cp++) if (*cp >= 'a' && *cp <= 'z') *cp ^= 040; len = (int)(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, */ /* unless it's NAK for next packet */ num = (--num<0 ? 63:num); 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 */ char 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, */ /* unless it's NAK for next packet */ num = (--num<0 ? 63:num); 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. */ 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, */ /* unless it's NAK for next packet, */ num = (--num<0 ? 63:num); 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) printf("\tClosing input file %s, ",filnam); fclose(fp); /* Close the input file */ fp = NULLPTR; /* Set flag indicating no file open */ if (debug) printf("looking for next file...\n"); if (gnxtfl() == FALSE) /* No more files go? */ return('B'); /* if not, break, EOT, all done */ if (debug) printf("\tNew 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) */ 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, */ /* unless NAK for previous packet, */ num = (--num<0 ? 63:num); 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() { char rinit(), rfile(), rdata(); /* Use these procedures */ state = 'R'; /* Receive-Init is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ while(TRUE) { if (debug) printf("\trecsw 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 */ char 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,len); /* Get the other side's init data */ len = spar(packet); /* Fill up packet with my init info */ 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 */ 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,NULLPTR); /* Return a NAK */ return(state); /* Keep trying */ default: return('A'); /* Some other packet type, "abort" */ } } /* * 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 too many tries "abort" */ if (oldtry++ > MAXTRY) return('A'); if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */ { /* Yes, ACK it again with */ 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,NULLPTR); numtry = 0; return(state); /* Stay in this state */ } else return('A'); /* Not previous packet, "abort" */ case 'F': /* File Header (just what we want) */ /* The packet number must be right */ if (num != n) return('A'); strcpy(filnam1, packet); /* Copy the file name */ if ((fp=(*kfopen)(filnam1,"w"))==NULLPTR) /* Try to open a new file */ { /* Give up if can't */ error("Cannot create %s",filnam1); return('A'); } else /* OK, give message */ printmsg("Receiving %s as %s",packet,filnam1); spack('Y',n,0,NULLPTR); /* 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,NULLPTR); /* 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,NULLPTR); /* Return a NAK */ return(state); /* Keep trying */ default: return ('A'); /* Some other packet, "abort" */ } } /* * r d a t a * * Receive Data */ char 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 previous packet again? */ spack('Y',num,0,NULLPTR); /* 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,NULLPTR); /* 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,NULLPTR); /* 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 */ /* Must have right packet number */ if (num != n) return('A'); spack('Y',n,0,NULLPTR); /* 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,NULLPTR); /* Return a NAK */ return(state); /* Keep trying */ default: return('A'); /* Some other packet, "abort" */ } } /* * c o n n e c t * * Establish a virtual terminal connection with the remote host, over an * assigned tty line. */ connect() { /* This routine assumes that iobyte has been fully implemented */ /* so that the program can check for input at the serial port. */ /* It assumes that the normal keyboard is the CRT: device. */ /* and the serial port is the TTY: device */ /* This routine is the one most likely to need changing for other machines */ register long iobyte; iobyte=bios(19) & ~3; printf("Connected\n"); while (1) { iobyte |=1; bios(20,iobyte); /* Set console device to keyboard */ /* Check for console input */ if (bios(2)) readcon(); iobyte &= ~3; /* Set console device to serial */ bios(20,iobyte); if (bios(2)) { iobyte |=1; bios(20,iobyte); bios(4,(long)(bios(7)& 0x7f)); } } } readcon() { /* This reads the console */ register int c; c=bios(3); /* Read the keyboard */ if (c!=0x1d) sendaux(c); /* If not CTRL ] */ else exit(0); } /* * KERMIT utilities. */ /* * s p a c k * * Send a Packet */ spack(type,num,len,data) char type, *data; int num, len; { int i; /* Character loop counter */ char chksum, buffer[100]; /* Checksum, packet buffer */ register char *bufp; /* Buffer pointer */ if (debug>1) /* Display outgoing packet */ { /* Null-terminate data to print it */ if (data != NULLPTR) data[len] = '\0'; printf("\tspack type: %c\n",type); printf("\t\tnum: %d\n",num); printf("\t\tlen: %d\n",len); if (data != NULLPTR) printf("\tdata: \"%s\"\n",data); } bufp = buffer; /* Set up buffer pointer */ for (i=1; i<=pad; i++) sendaux(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 */ sauxstr( buffer,(int)(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 */ do { t=readaux()& 0x7f; }while (t != SOH); /* Wait for packet header */ done = FALSE; /* Got SOH, init loop */ while (!done) /* Loop to get a packet */ { t=readaux(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum = t; /* Start the checksum */ *len = unchar(t)-3; /* Character count */ t=readaux(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum += t; /* Update checksum */ *num = unchar(t); /* Packet number */ t=readaux(); /* Get character */ if (t == SOH) continue; /* Resynchronize if SOH */ cchksum += t; /* Update checksum */ type = t; /* Packet type */ for (i=0; i<*len; i++) /* The data itself, if any */ { /* Loop for character count */ t=readaux(); /* Get character */ if (t == SOH) continue; /* Resynch if SOH */ cchksum += t; /* Update checksum */ data[i] = t; /* Put it in the data buffer */ } data[*len] = 0; /* Mark the end of the data */ t=readaux(); /* Get last character (checksum) */ rchksum = unchar(t); /* Convert to numeric */ t=readaux(); /* get EOL character and toss it */ if (t == SOH) continue; /* Resynchronize if SOH */ done = TRUE; /* Got checksum, done */ } if (debug>1) /* Display incoming packet */ { data[*len] = '\0'; /* Null-terminate data to print it */ printf("\trpack type: %c\n",type); printf("\t\tnum: %d\n",*num); printf("\t\tlen: %d\n",*len); printf("\tdata: \"%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 and 8-bit quoting is done; * repeat count prefixes are not handled. */ bufill(buffer) char buffer[]; /* Buffer */ { register int t; /* Char read from file */ register char t7; /* 7-bit version of above */ register char *buffend; /* End of buffer pointer */ register char *buffp; /* Pointer into buffer */ register int unprintable; /* Is a character printable ?*/ buffend = &buffer[spsiz-9]; /* set up end of buffer pointer */ buffp=buffer; /* and the current position */ while((t = getc(fp)) != EOF) /* Get the next character */ { t7 = t & 0177; /* Get low order 7 bits */ /* If doing 8-bit quoting, then quote if needed */ if ((t != t7) && qflag) *buffp++ = qbin; unprintable = ((t7=buffend) return((int)(buffp-buffer)); } if (buffp == buffer) return(EOF); /* Wind up here only on EOF */ return((int)(buffp - buffer)); /* 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 */ { register int i; /* Counter */ register char t; /* Character holder */ register int highbit; /* place to hold quoted highbit */ highbit = 0; for (i=0; i='!') && (qbin <= '>')) || ((qbin >= '`')&&(qbin <= '~'))) /* qflag = TRUE; */ en8quote(TRUE); /* jgc dec 25th. 1985 */ case 6: /* Incoming data quote character */ quote = data[5]; case 5: /* EOL character I must send */ eol = unchar(data[4]); case 4: /* Padding character I must send */ padchar = ctl(data[3]); case 3: /* Number of pads to send */ pad = unchar(data[2]); case 2: /* When I should time out */ timint = unchar(data[1]); if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME; case 1: /* Maximum send packet size */ spsiz = unchar(data[0]); case 0: break; } if (qflag) { if (qbin == 'N') error("Can't do 8 bit quoting\n"); else if (qbin == 'Y') qbin = QBIN; } } int readaux() { int c; c=bios(7); if (parity) c &= 0x7f; return (c); } sauxstr(buf,len) char *buf; int len; { for(;len>0;len--) sendaux(*buf++); } sendaux(c) int c; { /* A table giving even parity, used also to get odd parity */ static char partab[128]={ 0x00,0x81,0x82,0x03,0x84,0x05,0x06,0x87, 0x88,0x09,0x0A,0x8B,0x0C,0x8D,0x8E,0x0F, 0x90,0x11,0x12,0x93,0x14,0x95,0x96,0x17, 0x18,0x99,0x9A,0x1B,0x9C,0x1D,0x1E,0x9F, 0xA0,0x21,0x22,0xA3,0x24,0xA5,0xA6,0x27, 0x28,0xA9,0xAA,0x2B,0xAC,0x2D,0x2E,0xAF, 0x30,0xB1,0xB2,0x33,0xB4,0x35,0x36,0xB7, 0xB8,0x39,0x3A,0xBB,0x3C,0xBD,0xBE,0x3F, 0xC0,0x41,0x42,0xC3,0x44,0xC5,0xC6,0x47, 0x48,0xC9,0xCA,0x4B,0xCC,0x4D,0x4E,0xCF, 0x50,0xD1,0xD2,0x53,0xD4,0x55,0x56,0xD7, 0xD8,0x59,0x5A,0xDB,0x5C,0xDD,0xDE,0x5F, 0x60,0xE1,0xE2,0x63,0xE4,0x65,0x66,0xE7, 0xE8,0x69,0x6A,0xEB,0x6C,0xED,0xEE,0x6F, 0xF0,0x71,0x72,0xF3,0x74,0xF5,0xF6,0x77, 0x78,0xF9,0xFA,0x7B,0xFC,0x7D,0x7E,0xFF }; if (parity) { c &= 0x7f; switch(parity) { case 'o': case 'O': c=partab[c] ^ 0x80; break; case 'e': case 'E': c=partab[c]; break; case 'm': case 'M': c |= 0x80; break; /* Otherwise assume space parity */ } } bios(6,(long)c); /* Send character */ } /* * 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 */ { } /* * Kermit printing routines: * * usage - print command line options showing proper syntax * printmsg - like printf with "Kermit: " prepended * error - like printmsg * prerrpkt - print contents of error packet received from remote host */ /* * u s a g e * * Print summary of usage info and quit */ usage() { printf("Usage: kermit c[p[msoeN]]\t\t(connect mode)\n"); printf("or:\tkermit s[dqp[msoeN]] file ...\t\t(send mode)\n"); printf("or:\tkermit r[dqp[msoeN]]\t\t\t(receive mode)\n"); exit(1); } /* * 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("Kermit: "); printf(fmt,a1,a2,a3,a4,a5); printf("\n"); fflush(stdout); /* force output (UTS needs it) */ } /* * e r r o r * * Print error message. * * If local, print error message with printmsg. * If remote, send an error packet with the message. */ /*VARARGS1*/ error(fmt, a1, a2, a3, a4, a5) char *fmt; { printmsg(fmt, a1, a2, a3, a4, a5); } /* * p r e r r p k t * * Print contents of error packet received from remote host. */ prerrpkt(msg) char *msg; { printf("Kermit aborting with following error from remote host:\n%s\n", msg); return; } en8quote(t) int t; { /* jgc dec 25th. 1985 */ if (qflag = t) kfopen = fopenb; /* jgc dec 25th. 1985 */ else kfopen = fopen; /* jgc dec 25th. 1985 */ } /* jgc dec 25th. 1985 */