/************************************************************************ * * HD6KER.C Superkermit main source file and driver logic. * *********************************************************************** * * In ASCII mode only: * * LF is converted to CR/LF in transmission * and CR, LF, CR/LF or LF/CR to LF on receipt. * This code is in the machine-dependent routines. * * Following enhancements by: * * Frank Dreano (Code 431) * * 2403 Tarkington Ct. or Navy Management System Support Office * Chesapeake, Va. 23322 1441 Crossways Boulevard * (804) 421-3785 Chesapeake, Va. 23320-8915 * (804) 523-8190 * * Jun 1988 - binary transfers now supported by correcting two bugs in * bufill() and encode()...this Kermit now precreates the right type * file. The PC Kermit must NOT use CTRL-Z for end-of-file marker! * * Jul 1988 - added routines to do type-1, type-2 and type-3 checksums * to support critical file transfers, typically binary. Also, * added routine to decode repeat-prefixed incoming filenames in * keeping with 'classic' Kermit. These routines are chk1(), chk2(), * chk3() and decfil() respectively. * * Aug 1988 - long packets implemented if they can be negotiated with the * micro Kermit, otherwise 'classic' Kermit is used. If the other side * can use extended packets then the length is negotiated as follows: * * If no remote extended packet length is specified but the CAPAS * extended bit is set then the default is 500. * If the remote's extended packet length is less than mine, then * that length is used, else mine (2000) is used. * * Changed spack() and rpack() routines to use register variables * and address pointer arithmetic to improve efficiency since * CRC integrity checks are expensive. Added a 'generic' error message * routine, syserr(), to send error packets for either UNIX/Kermit * or MOD400 type errors. * * Sep 1988 - implemented file attribute packets (definitely one of my * better efforts) to send file sizes back and forth for transfers; if * this capability is requested. This allows the user to see approximate * percentages of data transfered to the PC during file receives. * The MOD400 file size is determined by the fsize() routine and the file * size will NOT be estimated for variable-length record files as there * is NO way of knowing how many records/CI there are without reading * each record. If this option produces ANY problems at all turn * off the file attributes on the PC Kermit and bypass this feature. * This capability allows binary files on the DPS-6 to be precreated at * the right size instead of growing all over the disk in 32 Control * Interval file management extents. Also greatly simplified DPS-6 * Superkermit command-line arguments and invocation. * * Dec 1988 - added support for the 4.0 operating system...the SOH char * is ^F for 3.1 and ^A for the 4.0 operating systems. The PC Kermit * can use this info to take appropriate action (e.g. to not repeat * the outgoing 'hide' character in 4.0 ... see notes below). * * Mar 1989 - due to Honeywell's Kermit having to run in an inefficient * MOD400 'swappool' under 4.0 operating system, Superkermit was made * more generic and now works with VIP3 and MOD400 4.0 ONLY!. The VIP3 * Terminal Emulator must be configured for the '7-bit other host' Kermit * file transfer option. Although packet sizes are limited to 94 bytes * I feel that this is more than compensated for by Superkermit's fast * turn-around; no interpacket pacing delays. Superkermit also pre- * creates DPS-6 'fixed relative' files for binary transfers. VIP3 * appends a ',I' string to incoming binary filenames and Superkermit * rips it out. Added ability to date/time stamp debug file data via * the new get_time() routine. * * Jan 1990 - MOD400 4.0 can now run terminal lines with eight bits of * data and no parity...therefore 8-bit 'binary-image' mode was * re-implemented for more efficient (no-prefixing) binary transfers. * Also made 2000-byte extended packets available for compatibility * with MSKermit 3.0 and up. * * Aug 1990 - fixed a problem in the nextin() routine which caused a * coredump when the third level of debugging (-DDD) was turned on * when SUPERKERMIT was receiving a file as discovered by Tim Ewing * from Honeywell's Maclean office. * * Sep 1990 - figured out a way to perform wild card 'sends' to a micro * while in server/send mode using the star_name() function. This * will ship up to 100 files of the type specified in the command * line (e.g. ASCII or BINARY); other file types will be skipped. * File types are: F_R = BINARY; SEQ, S_R = ASCII. This routine * uses the Honeywell 'heap' to build the filename list so the code * grew some and the compiler EC has changed (see below). Also added * the ability to do many 'advanced' Kermit server commands; see the * internal documentation below. It is strongly recommended that these * new capabilities only be used on a Honeywell 4.0 operating system * (due to Superkermit's increased size) and with MSKermit 3.02 or * later (3.02 fixed many 'remote' command bugs). Finally, (thanks * again to Tim Ewing of Honeywell Maclean) there is a way to store * all types of MSDOS files (e.g. text, *.COM, *.EXE, *.WKS, etc.) on * the DPS-6 and bring them back alive to the PC using MSKermit. * A new Superkermit command line argument 'F' designates a 'foreign' * (usually MSDOS) file type and invokes special Honeywell disk storage * methods. Unfortunately, the MSKermit 'remote set file type' server * command only has 'text' and 'binary' arguments, so to change the file * transfer mode to 'foreign' I have implemented a special Kermit * command on the micro: 'remote kermit foreign'. Modified fsize() to * also determine if a sequential file is being used for foreign data * storage so wilcard gets work correctly. Found and fixed more bugs * than I care to mention with fprintf() statements to the debug file. * * Performed a much-needed reorganization of code; all possible 'C' * preprocessor and global/external variable/functions are now in * a separate hd6ker.h include file. With all of these changes, the * program has been given a new major release number of 2.00. * * Dec 1990 - fixed a long-standing bug in binary file sending...the * spar() routine defaulted to a 'Y' in the 8th-bit quoting field * of the send-init packet; this means that I (Superkermit) do not * require 8th-bit quoting - a usually false assumption. Instead * the usual default char of '&' is now the default if no character * is received from the other Kermit. * * Apr 1991 - implemented the 'remote space' command as a MOD400 * STS -ALL command as MSKermit 3.10 fixed a bug in this function. * * The above enhancements are per the Kermit Protocol Manual * as distributed from Columbia University, Frank da Cruz. * *********************************************************************** * * Typical ASCII file transfer (7-bit only, extended packets): * * SUPERKERM S/R/VA [file1 file2 etc.] * * Typical binary file transfer (8-bit prefixed, extended packets): * * SUPERKERM S/R/VB [file1 file2 etc.] * * MOD400 'save' files may be shipped in binary mode if the save was * done to a pre-created 'fixed-relative' type file. * * This Kermit has been successfully tested at speeds up to 19,200 bps * and also works on the Honeywell AP6 microcomputer. HOWEVER, unless * you KNOW that your environment can handle extended packets, CRC-type * block checks etc., stick to 'classic' Kermit with 94-byte packets, * 1-character block checks and speeds at or under 9600 bps. The PC * Kermit used with the DPS-6 must be modified to deliver 2 backslash * (\) characters when one is desired in outgoing packets as the terminal * driver on the Honeywell consumes the first one even in 'raw' mode. * This extra char should not be figured in any checksum or length * computations. This is only necessary with the 3.1 operating system as * the 'hide' char in 4.0 is ^P. If extended packets over 127-bytes are * desired for either the 3.1 OR the 4.0 Honeywell operating system then * the PC Kermit must be modified to consume incoming LF (0AH) characters * in its rpack() routine, these should also not be figured into checksum * or length computations. This is necessary as the Honeywell sends a * post write-order LF char at the end of 134-byte buffer writes regard- * less of the packet length. If these mods only activate during DPS-6 * file transfers then the PC Kermit is still generic for all other * systems. These two mods were implemented in the MSSCOM.ASM module * of MSKERMIT Ver. 3.00 (Columbia University). This Kermit requires the * DPS-6 Scientific Instruction Processor or an equivalent simulator. * * WARNINGS / DISCLAIMERS / CAVEAT EMPTOR / ETC. * ============================================= * * NO warranty is expressed or implied and the suitability of this * product for a particular application must be determined by the user. * * Kermit is a copyrighted product of Columbia University. As always * it may be freely distributed and copied as long as it remains in * its complete form with these comments included. This particular * Kermit was produced using U.S. Government time and materials. * * * An EC to build executable Superkermit is as follows: * * &N * M4_CC HD6KER.C -OP -AS -SZ 32 -V * M4_CC HD6PRI.C -OP -AS -SZ 32 -V * LD SUPERKERM -LK HD6KER HD6PRI -SZ 32 -V -NL * & * & The editor routine below saves about 9 Kwords * & by nuking extra 'heap' space unused by Superkermit. * & It also creates a more detailed link map by * & using the MAP versus the MAPD linker directive. * & * &A * >SYSLIB2>ED?SILENT * R SUPERKERM.Q * /HSIZE/ S/X'./X'B/ * /MAPD/ S/MAPD/MAP/ * W * Q * &D * >SYSLIB2>LINKER SUPERKERM -IN SUPERKERM.Q -SZ 32 * &F * &Q * * If you want a 'shareable/reentrant' version append the '-R' * argument to the two 'M4_CC' lines and the 'LINKER' line * above. It will then run only in a swappool however! * ********* End of introductory comments.....Frank Dreano ************ */ #define MAINDEF /* allows the inclusion of necessary global stuff */ #include "hd6ker.h" /* * 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, **argv1; int argc1; unbuffer(); /* unbuffer output */ printf("%s", ident); aflg = sflg = rflg = 0; /* Turn off all parse flags */ cp = *++argv; argv1 = argv; /* remember argument pointers */ argv++; argc1 = --argc; --argc; /* pointers to args */ /* 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 xnull if any padding wanted */ spsiz = 94; /* set up max packet length */ qu8 = 0; /* Assume 7-bit */ image = -1; /* ASCII file transfer */ ofi = fileimage = ASCII; /* at first. */ rptflg = TRUE; /* try for repeating */ dlflag = TRUE; /* Overwrite incoming files */ filnamcnv = FALSE; /* conversion for UNIX systems */ sattrib = FALSE; /* attribute packets off */ senda = TRUE; /* I have attribute capability */ slongp = TRUE; /* extended packets on */ dfp = 0; dname = 0; /* clear debug file ptrs */ /* signal(SIGALRM,timoex); initialize signal catcher */ if (argc >= 0) while ((*cp) != NULL) switch (*cp++) { /* If command-line, parse characters in first arg. */ case 'H': case 'h': debug = 0; help(); /* H = help messages */ case 'V': case 'v': aflg++; break; /* V = Server command */ case 'I': case 'i': /* I = 8-bit image */ image = 1; ++iflg; break; case 'R': case 'r': rflg++; break; /* R = Receive command */ case 'S': case 's': sflg++; break; /* S = Send command */ case 'F': case 'f': ofi++; fileimage = FOREIGN; /* B = Foreign file type */ break; case 'B': case 'b': ofi++; fileimage = BINARY; /* B = Binary transfer */ break; case 'A': case 'a': image = 0; /* 7 = Ascii 7-bit transfer */ ++iflg; ofi++; break; case 'C': case 'c': dlflag = FALSE; /* C = Concat to incoming files */ break; case '-': break; /* - flag swallowed */ default: --cp; printmsg("Invalid char %c in command-line.",*cp); usage(); } if (image == -1) { /* default is 8-bit prefixed */ image = 2; ++iflg; } oimage = image; /* remember tseting */ if (ofi > 1) { printmsg("One only of \"A\", \"B\" or \"F\" arguments!"); usage(); } ofi = fileimage; /* remember filetype */ /* Flags parsed, check for debug filename */ cp = *argv; if (*cp == '-') { if (*++cp != 'D') { /* invalid debug filename */ printmsg("Debug filename <%s> must start with \"D\".",*--cp); usage(); } while (*cp == 'D') { /* count the Ds */ ++debug; ++cp; } if (debug > 3) usage(); /* no more than 3 'D's */ dname = cp; /* filename starts after Ds */ dfp = fopen(dname,"a"); ++argv; --argc; } if ((c = aflg+sflg+rflg) > 1) { /* Only one command allowed */ printmsg("One only of Server OR Receive OR Send!"); usage(); } if (iflg > 1) { printmsg("One only of \"I\" or \"A\" arguments!"); usage(); } if (c == 0) { /* no action-flag */ printf(crlf); printmsg("No action on command-line; Server mode assumed;\n For help type \"superkerm h\"."); aflg = 1; } /* Put the tty into the correct mode */ rawtty(); /* All set up, now execute the command that was given. */ if (debug) { if (dfp != 0) { printmsg("Debugging level = %d into file \"%s\";",debug,dname); fprintf(dfp,"\n\n******** Superkermit Debug File ** next run starts here **********\n"); fprintf(dfp,"%s", ident); get_time(); fprintf(dfp,"\nDebugging level = %d into file \"%s\";\nCommand-line: <",debug,dname); while (argc1-- > 0) fprintf(dfp," %s",*argv1++); fprintf(dfp," >;"); if (aflg) fprintf(dfp,"\nServer Command\n"); if (sflg) fprintf(dfp,"\nSend Command\n"); if (rflg) fprintf(dfp,"\nReceive Command\n"); } else { printf("No valid debug file, debug switched off.\r\n"); debug = 0; } } /* --- get BU size for operating system version and print time stanp --- */ fsize(buname,3); if (sflg) /* Send command */ { if (argc--) { sysint = system(tset); printmsg("Send Command; set your Kermit to receive files\n"); filnam = *argv++; /* Get file to send */ } else { cooktty(); /* restore tty to normal */ printmsg("Send, but no filename given;\n"); usage(); /* and give error */ } /* check for wildcards else do the old stuff */ if ((star_check(filnam)) == -1) { fp = NULL; filelist = argv; /* Set up the rest of the file list */ filecount = argc; /* Number of files left to send */ for (timflag=0; timflag<8; ++timflag) {sleep(1);} if (sendsw() == FALSE) /* Send the file(s) */ printmsg("Send failed."); /* Report failure */ } else { if (debug) fprintf(dfp,"\n Parsing wildcard name <%s>\n", filnam); wildname(filnam); filelist = filenames; if (filecount--) { filnam = *filelist++; fp = NULL; if (sendsw() == FALSE) { /* send the files */ if (fp != NULL) fclose(fp); printmsg("Send failed."); /* Report failure */ } } /* end if */ } /* end else */ } /* end sflag */ else if (rflg) { /* Receive command */ sysint = system(tset); if ((debug) && (m4_errno != 0)) fprintf(dfp,"\nsystem call error = %d", m4_errno); printmsg("Receive Command; set your Kermit to Send files\n"); for (timflag=0; timflag<5; ++timflag) { sleep(1);} timint = 20; if (recsw() == FALSE) /* Receive the file(s) */ printmsg("Receive failed."); } else while (aflg) { /* server mode */ sysint = system(tset); printmsg("Server Command; set your Kermit to Send or Get files;"); getdir(attrib, -1); /* get users home directory */ strcat(attrib,"/$KERMIT$.TMP"); pthto6(attrib, fo_name); if (fileimage != ASCII) oimage = image; /* keep ORIGINAL BINARY/FOREIGN image flag */ else oimage = 0; if (autosw() == TRUE) { printmsg("Server Send/Get complete"); sprintf(cmdstg, ">SYSLIB2>DL %s -BF", fo_name); system(cmdstg); } else { /* --- logout of the DPS-6 if user requested if --- */ printmsg("Server-mode cancelled"); closeall(); cooktty(); sysint = system(tclr); printmsg("done."); system(byenow); /* Log out of DPS-6 */ exit(0); } /* end else */ } closeall(); cooktty(); sysint = system(tclr); printmsg("done."); /* if (c == 'L') system(byenow); Log out of DPS-6 if requested */ exit(0); } /* End main() */ /* * a u t o s w * * autosw is the state table switcher for automatic mode. It loops * until it finishes or an error is encountered. The called routines * are responsible for changing the state * */ autosw() /* state switcher for automatic mode */ { int len, num; char c, *ap, *wild; forever { timint = 40; /* slow NAKs at first */ bctu = 1; /* assume type-1 blk chk at first */ senda = TRUE; sattrib = FALSE; /* attribute packets off */ if (debug) fprintf(dfp, "\nServer setup: Fileimage: %d, image: %d, q_char: %c, rptflg: %s, bchk: %d.", fileimage,image,qu8,logicval[-rptflg],bctu); /* "\nServersw() set: 8th-bit tseting is %d, char is %c, reptflag %s, chktype %d.", image,qu8,logicval[-rptflg],bctu); */ n = numtry = 0; switch ( (type = rpack(&len,&num,recpkt)) ) { /* decipher request from micro */ case 'S': /* SEND */ /* receive file(s) from local Kermit */ state = 'F'; bctu = 1; /* assume type-1 blk-chk */ rpar(recpkt,len); len = spar(packet); spack('Y',n,len,packet); /* ack parameters */ n = (n+1)%64; bctu = bctr; /* use agreed upon blk-check from now on */ while (state != 'C') { /* until EoF */ if (debug == 1) fprintf(dfp," serversw state %c\n",state); switch(state) { case 'F': state = rfile(); break; case 'D': state = rdata(); break; case 'A': /* upload aborted */ state = 'C'; break; case 'C': break; } } /* end switch, while */ fileimage = ofi; /* If original BINARY/FOREIGN image never given default to prefixed !!! */ if (fileimage == ASCII) image = 0; else { if (oimage == 0) image = 2; else image = oimage; } break; /* end of reception */ case 'R': /* GET */ /* send file(s) to micro Kermit */ if (debug) fprintf(dfp,"\n getting files <%s>, ", recpkt); decfil(recpkt,getfiles,len); TYPE: /* process wildcards if star name else do the old stuff */ if ((star_check(getfiles)) == -1) filecount = decol8(getfiles,filenames,10); else wildname(getfiles); filelist = filenames; if (debug > 1) { fprintf(dfp,"\n %d files, ",filecount); while (*filelist != 0) fprintf(dfp,"<%s> ",*filelist++); filelist = filenames; } if (filecount--) { /* if any valid names */ filnam = *filelist++; fp = NULL; if (sendsw() == FALSE) { /* Send the file(s) */ if (fp != NULL) fclose(fp); printmsg("Send failed."); /* Report failure */ } /* end if */ else printmsg("Files sent; still in server-mode."); } else /* if no names */ error(noname,prompt); fileimage = ofi; /* If original BINARY/FOREIGN image never given default to prefixed !!! */ if (fileimage == ASCII) image = 0; else { if (oimage == 0) image = 2; else image = oimage; } iflg = 0; /* reset flag to xfer and not type files */ break; case 'I': /* INFO PACKET */ bctu = 1; /* use type-1 blk chk at first */ rpar(recpkt,len); len = spar(packet); spack('Y',n,len,packet); /* ack the parameters */ bctu = bctr; /* its safe to use agreed blk chk now */ break; case 'E': /* ERROR PACKET */ prerrpkt(recpkt); aflg = 0; error(goodbye,prompt); return(FALSE); break; case 'N': /* NAK */ error(amauto,prompt); break; case FALSE: /* TIMEOUT ON MICRO */ printf(crlf); printmsg("Please enter Kermit server command to micro Kermit,"); printf("\t(or send ESCAPE-C to cancel Superkermit) ...\n"); spack('N',0,0,xnull); break; case 'G': /* KERMIT SEVER COMMAND */ if (len > 1) { decfil(&recpkt[1],attrib,(len-1)); strcpy(getfiles, &attrib[1]); if (debug) fprintf(dfp,"\nDecoded server cmd argument: %s\n", getfiles); } switch (c = *recpkt&0x5f) { case 'F': /* FINISH */ len = strlen(goodbye); spack('Y',num,len,goodbye); aflg = 0; return(TRUE); break; case 'L': /* LOGOUT */ len = strlen(logout); spack('Y',num,len,logout); aflg = 0; return(FALSE); break; /* --- Following routines implement advanced Kermit server features --- */ /* --- This stuff will only work right with MSKermit 3.02 or later. --- */ /* --- Short results are returned in a packet; long in a file xfer. --- */ case 'S': /* SERVER SET FUNCTION */ /* The 'trick' string in the next line was obtained by logging MSKermit 3.01/3.02 packets and not thru ANY documentation. */ if ((strncmp(getfiles, "300!", 4)) != 0) { len = strlen(hostng); spack('Y',num,len,hostng); } else { len = strlen(hostok); spack('Y',num,len,hostok); if(getfiles[4] == '0') { /* Text mode */ ofi = fileimage = ASCII; image = 0; } if(getfiles[4] == '1') { /* Binary mode */ ofi = fileimage = BINARY; /* If original BINARY/FOREIGN image never given default to prefixed !!! */ if (oimage == 0) image = 2; else image = oimage; } } break; case 'M': /* OPERATOR MESSAGE */ case 'E': /* DELETE FILE(S) */ case 'C': /* CHANGE WORKING DIR */ if (c == 'C') { strcpy(cmdstg, getfiles); pthto6(cmdstg, getfiles); sprintf(cmdstg, ">SYSLIB2>CWD %s", getfiles); } if (c == 'E') sprintf(cmdstg, ">SYSLIB2>DL %s -BF", getfiles); if (c == 'M') sprintf(cmdstg, ">SYSLIB2>MSG \"%s\"", getfiles); cmdstat = 0; if ((cmdstat = system(cmdstg)) != 0) { if (debug) fprintf(dfp, "\nGeneric server cmd: %c, with arg: %s failed\n", c, getfiles); len = strlen(hostng); spack('Y',num,len,hostng); } else { if (debug) fprintf(dfp, "\nGeneric server cmd: %c, with arg: %s succeeded\n", c, getfiles); if (c == 'C') getcwd(cmdstg, 80); len = strlen(cmdstg); spack('Y',num,len,cmdstg); } /* end else */ break; case 'T': /* TYPE A FILE */ /* set the unused iflg variable and jump upto the 'R' to send the file */ fileimage = ASCII; iflg = 99; if (debug) fprintf(dfp,"\n Typing file <%s>, ", getfiles); goto TYPE; break; case 'D': /* DIRECTORY LISTING */ sprintf(cmdstg,">SYSLIB2>LS %s", getfiles); goto WHO; break; case 'W': /* WHO IS ON */ sprintf(cmdstg,">SYSLIB2>VIDEO -G ALL -PAGES 1"); goto WHO; break; case 'U': /* DISK SPACE */ sprintf(cmdstg,">SYSLIB2>STS -ALL"); goto WHO; break; default : error(onlyg,prompt); break; } /* end inner switch */ break; /* break for outer switch */ case 'K': /* SPECIAL KERMIT COMMAND */ decfil(recpkt, getfiles, len); if (debug) fprintf(dfp,"\nKermit cmd: %s\n", getfiles); if ((strncmp("IMAGE",getfiles,5) == 0) || (strncmp("image",getfiles,5) == 0)) { oimage = 1; if (fileimage != ASCII) image = 1; len = strlen(hostok); spack('Y',num,len,hostok); } else if ((strncmp("PREFI",getfiles,5) == 0) || (strncmp("prefi",getfiles,5) == 0)) { oimage = 2; if (fileimage != ASCII) image = 2; len = strlen(hostok); spack('Y',num,len,hostok); } else if ((strncmp("FOREI",getfiles,5) == 0) || (strncmp("forei",getfiles,5) == 0)) { ofi = fileimage = FOREIGN; /* preserve ORIGINAL image mode!!! */ if (oimage == 0) image = 2; else image = oimage; len = strlen(hostok); spack('Y',num,len,hostok); } else error(onlyg, prompt); break; case 'C': /* MOD400 COMMAND */ /* The safest way to do MOD400 commands is via I/O redirection...the DPS-6 command results are sent to a Honeywell file (named $KERMIT$.TMP) and this file is then sent to the PC starting with an 'X' instead of an 'F' Kermit packet. This notifies MSKermit that the file should be typed to the microcomputer screen and not stored on disk. Unfortunately the DPS-6 directory delimiter char is '>' which is ALSO the MSDOS I/O redirection symbol. MSKermit host server commands doing DPS-6 directory stuff almost never deliver proper directory names unless they operate only in the working directory. Therefore you must do things like: remote cwd /UDD/DREANO { UNIX style ! } remote host CD MYDIR and NOT remote host CD >>UDD>DREANO>MYDIR !!! This makes some things hard and others impossible, but thats life. Frank Dreano */ decfil(recpkt, getfiles, len); filecount = decol8(getfiles,filenames,10); filelist = filenames; filecount--; filnam = *filelist++; sprintf(cmdstg, "%s", filnam); while (filecount-- > 0) { /* add on any command arguments */ strcat(cmdstg," "); filnam = *filelist++; strcat(cmdstg, filnam); } /* end while */ WHO: fileimage = ASCII; iflg = 100; /* load up the bound unit name */ sprintf(cmdstring, ">SYSLIB2>DL %s -BF", fo_name); system(cmdstring); sleep(1); sprintf(cmdstring, ">SYSLIB2>FO %s", fo_name); system(cmdstring); sprintf(cmdstring, ">SYSLIB2>FO %s -EO", fo_name); system(cmdstring); if (debug) fprintf(dfp,"\nExecuting: %s \n", cmdstg); cmdstat = system(cmdstg); system(">SYSLIB2>FO -RESET -EO"); system(">SYSLIB2>FO -RESET"); sleep(1); decfil(fo_name,getfiles,strlen(fo_name)); goto TYPE; break; /* --- --- */ /* --- End of advanced Kermit server features --- */ /* --- --- */ default: /* BAD PACKET */ error(badpack,prompt,type); return(FALSE); } } /* end switch, forever */ } /* End autosw() */ /* * b u f i l l * * Get a bufferful of data from the file thats being sent * */ bufill(buffer) char *buffer; { int t, i; static int softeof= FALSE; if (softeof == TRUE) { softeof = FALSE; return(EOF); } rpt = sz = 0; /* Inits for encode() */ dt = buffer; oldt = -2; /* impossible last char */ if (iflg == 100) { /* skip encoding, packetizing and slew byte */ for (i=0; i < 132 && (t=fgetc(fp)) != EOF; ++i) { if (i==0) continue; t = ascedit(t); /* edited if necessary */ encode(t); /* to buffer */ if (t == '\n') break; } /* end for */ if (sz==0) goto EOFPROC; else return(sz); } else { while((t = getc(fp)) != EOF) { /* next character */ t = ascedit(t); /* edited if necessary */ encode(t); /* to buffer */ if (sz >= spsiz-(7+bctu)) /* Check length */ return(sz); } /* end while */ } /* end else */ /* reach here on (hard) EOF or error */ EOFPROC: if (sz==0) return(EOF); else { softeof = TRUE; return (sz); } } /* end of bufill() */ /* * c l o s e a l l * * Close both the input/output file and the debug file * */ closeall() { if (fp != NULL) fclose(fp); if (dfp != NULL) { get_time(); /* print stop time to debug file */ fprintf(dfp,"\n\n************************* End of Run ******************************\n\n"); fclose(dfp); } } /* end of closeall() */ /* * c r e a d * * Gets the next character from the terminal line; * detects Kermit escape sequences; returns SOH and * printables, eats all other control characters * */ char cread() { char c, t; int ex; ex = 0; while (ex == 0) { t = nextin(); /* get next char */ /* if (timflag == 0) return(0); timeout occured */ c = t&0x7f; if (image != 1) t = c; if ( (c == CR) || (c == LF) || (c == SOH) || (c > 0x1f) ) return(t); /* left only with invalid controls */ if (c == ESC) { /* process escape */ printf("\nSuperkermit-ESC"); Repeat: /* for ignoring "-" */ t = nextin(); c = t&0x5f; if (c == SOH) return(t); switch(c) { /* case SOH: return(t); */ case 'C': cooktty(); printf("\nSuperkermit terminating by ESC-C from local station\n"); closeall(); sysint = system(tclr); exit(0); break; case 'H': printf("\n\rSuperkermit is alive and well ....\n\r"); break; case 'Q': cooktty(); system(tclr); printf("\n\rSuperkermit spawning command shell ... &Q to return\n"); system(">SYSLIB2>EC ![TERM_ID]"); system(tset); rawtty(); break; case 0x1f: /* ? */ case 0x0f: /* / */ cooktty(); system(tclr); help1(); system(tset); rawtty(); break; case '-': goto Repeat; default: printf("???"); break; } } } return(0); } /* End of cread() */ /* * d e c o d e * * Routine to decode incoming packets, returns 0 or an error-code * */ decode(buf,len) char *buf; int len; { char a, a7, b8, *end, rep; int flg8=0, error=0, r; end = buf + len; while (buf < end) { a = *buf++; if ( rptflg && (a == '~') ) { /* got a repeat prefix? */ rep = unchar(*buf++); /* Yes, get the repeat count, */ a = *buf++; /* and get the prefixed character. */ } else rep = 1; b8 = 0; /* Check high order "8th" bit */ if ( (image == 2) && (a == qu8) ) { b8 = 0200; a = *buf++; /* and get the prefixed character. */ } if (a == quote) { /* If control prefix, */ a = *buf++; /* get its operand. */ a7 = a & 0177; /* Only look at low 7 bits. */ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */ a = ctl(a); /* if in control range. */ } a = a | b8; /* OR in the 8th bit */ while (rep-- > 0) { if (image == 0 || fileimage == ASCII) /* if 7-bit */ r = ascout(a); else { /* prefixing / image */ r = putc(a,fp); } if (r == EOF) /* if error */ error |= filerr(); } } return(error); } /* end of decode() */ /* * d e c o l 8 * * Splits up command line into sections delimited by blanks, * zeros all such chars & places start-addresses into array, * up to maximum of num entries; zeros rest of entries and * returns count of valid entries. * */ decol8(line,arr,num) char *line, *arr[], num; { char c, count, *start; int i, j; j = count = 0; start = line; for (i=0; i<80, j 0) { arr[j++] = start; count = 0; } if (c == 0) break; /* out of for */ } else if (count++ == 0) /* printable */ start = &line[i]; /* start next parm */ } /* end else, for */ line[i] = 0; /* terminate last parm */ i = j; /* number of parms */ while (j < num) arr[j++] = 0; /* clear garbage */ return(i); } /* End of decol8() */ /* * e n c o d e * * Encode single character into packet for transmission * */ encode(a) int a; /* char to be encoded */ { int a7; /* Low order 7 bits */ int b8; /* 8th bit of character */ int flg8 = 0; static int oldsz; if (image == 2) flg8 = -1; if (rptflg) { /* repeat-count processing */ if ((a == oldt) && ((a & 0x00FF) != 0xFE)) { /* char is same and NOT -2 */ /* This code is simple but relatively inefficient; it stores the repeat flag, count and character each time around so that when the run is broken the buffer is valid; also it treats a pair as a run, which requires 3 bytes not 2 unless the pair is control- or 8bit-prefixed; but it does not require lookahead logic from the data-read. */ sz = oldsz; /* wind back pointer */ dt[sz++] = '~'; /* store prefix */ dt[sz++] = tochar(++rpt); /* & count */ if (rpt > 93) /* force new start */ oldt = -2; /* impossible value */ } /* end inner if */ else { /* not run, or end */ rpt = 1; oldt = a; /* save char */ oldsz = sz; } /* end else */ } /* end outer if */ a7 = a & 0177; /* Isolate ASCII part */ b8 = a & 0200; /* and 8th (parity) bit. */ if (flg8 && b8) { /* Do 8th bit prefix if necessary. */ dt[sz++] = qu8; a = a7; } if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ dt[sz++] = MYQUOTE; a = ctl(a); } if (a7 == MYQUOTE) /* Prefix the control prefix */ dt[sz++] = MYQUOTE; else if (rptflg && (a7 == '~')) /* If it's the repeat prefix, */ dt[sz++] = MYQUOTE; /* quote it if doing repeat counts. */ else if (flg8 && (a7 == qu8)) /* Prefix the 8th bit prefix */ dt[sz++] = MYQUOTE; /* if doing 8th-bit prefixes */ dt[sz++] = a; /* Finally, insert the character */ dt[sz] = '\0'; /* itself, and mark the end. */ return; } /* end of encode() */ /* * g n x t f l * * Get next file in a file group * */ gnxtfl() { if (debug) fprintf(dfp,"\n gnxtfl: filelist = \"%s\"",*filelist); filnam = *(filelist++); if (filecount-- == 0) return FALSE; /* If no more, fail */ else return TRUE; /* else succeed */ } /* End gnxtfl() */ /* * d e c f i l * * This routine decodes repeat-prefixed, control-prefixed * incoming filenames and Kermit server advanced commands. * It assumes that such items are 7-bit ASCII ONLY !!! * [FRANK DREANO] */ decfil(buf, to, len) char *buf, *to; int len; { char a, *end, rep; end = buf + len; while (buf < end) { a = *buf++; if (a == '~') { rep = unchar(*buf++); a = *buf++; } /* end if */ else rep = 1; if (a == quote) { a = *buf++; a &= 0177; if ((a >= 0100 && a <= 0137) || a =='?') a = ctl(a); } /* end if */ while (rep-- > 0) *to++ = a; } /* end outer while */ *to = '\0'; return; } /* end decfil */ /* * r e c s w * * This is the state table switcher for receiving files * */ recsw() { if (debug) fprintf(dfp,"Ready to receive file\n"); state = 'R'; /* Receive-Init is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ forever { if (debug == 1) fprintf(dfp," 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 */ } } } /* End recsw() */ /* * 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() { if (debug) { fprintf(dfp,"\nSendsw() sending file; "); } state = 'S'; /* Send initiate is the start state */ n = 0; /* Initialize message number */ numtry = 0; /* Say no tries yet */ forever { /* Do this as long as necessary */ if (debug == 1) fprintf(dfp," sendsw state: %c\n",state); switch(state) { /* 'Q' state is for attributes ONLY! */ case 'Q': state = sattru(); break; /* Send-Attributes */ 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 */ } } } /* End sendsw() */ /* * s y s e r r * * Routine to provide generic error reporting of either * UNIX or MOD400 type errors. [FRANK DREANO] * */ syserr(msg) char *msg; { char sherr[25], errstg1[50], errstg2[10]; int status; extern int errno, sys_nerr; extern char *sys_errlist[]; /* --- print MOD400 error if its a "system" ECL command request --- */ if ((status = strncmp(msg, "syst", 4)) == 0) { sprintf(errstg1, "%sError occurred in MOD400 command: 0%x",prompt,m4_errno); sprintf(sherr, ">SYSLIB2>DISPLAY 0%x", m4_errno); if ((status = system(sherr)) != 0) fprintf(stderr, "MOD400 error not in message library. \n"); error(errstg1); /* ship error packet out */ } /* end if */ /* --- if its a UNIX type error print MOD400 equivalent, if possible, then print the UNIX version of the error --- */ else { if (((m4_errno - errno) != 0x1800) && (m4_errno > 0) && (m4_errno < 0x9999)) { fprintf(stderr, "Error occurred in MOD400 system service call. \n"); sprintf(sherr, ">SYSLIB2>DISPLAY 0%x", m4_errno); if ((status = system(sherr)) != 0) fprintf(stderr, "Error not in message library. \n"); } /* end if */ sprintf(errstg1, "%sERROR: %s (%d",prompt, msg, errno); if (errno > 0 && errno < sys_nerr) sprintf(errstg2, ": %s)\n", sys_errlist[errno]); else sprintf(errstg2,")\n"); strcat(errstg1, errstg2); error(errstg1); /* send error packet out */ } /* end else */ } /* end syserr */ /* * g e t _ t i m e * * function to print start/stop time to debug file in the form: * Thu May 25 07:50:15 1989 */ get_time() { struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; } *localtime(); long time(), tloc; char *asctime(), *ltime; tloc = time ( (long *) 0); ltime = asctime(localtime(&tloc)); if (debug) fprintf(dfp, "\n\t Time stamp: %s\n", ltime); return(0); } /* end get_time */ /* * a s c e d i t * * This routine converts unix LF end-of-line to CR/LF * iff in 7-bit mode prior to sending the character. * Returns the modified character. * */ char ascedit(c) char c; { if (image == 0 || fileimage == ASCII) { /* only if 7-bit */ c &= 0x7f; if (c == LF) encode(CR); /* CR of CR/LF; */ } /* bufill() adds the LF */ return(c); } /* End of ascedit() */ /* * a s c o u t * * This routine writes 7-bit data to file as it is received * and is not used for 8-bit data, either image or 8-prefixing * */ char ascout(a) char a; { char ret; static char olda = 0; /* for dps6, replace each CR, LF or CR/LF or LF/CR by a single LF */ if (a == SUB) { ret = olda = 0; return (ret); } if ( ( (a == CR) && (olda == LF) ) || ( (a == LF) && (olda == CR) ) ) ret = olda = 0; else { /* if not CR/LF pair */ olda = a; if (a == CR) a = LF; /* CR => LF for unix */ ret = putc(a,fp); } return (ret); } /* End of ascout() */ /* * f i l e r r * * This routine is called when EOF is encountered reading or * writing the data file, if truly and EOF it returns 0 or * else a system error code * */ char filerr() { char ret; ret = ferror(fp); clearerr(fp); return(ret); } /* End of flerr() */ /* * f l u s h i n p u t * * Dump all pending input to clear stacked up NAKs * */ flushinput() /* DHS 1.0 version */ { /* ioctl(0,TIOCFLUSH,0); */ return; } /* End of flushinput() */ /* * c o o k t t y / r a w t t y * * Routines to set terminal input into "raw" or "cooked" mode. * */ static char cookedok = 0; cooktty() /* restore terminal state */ { /* if (cookedok != 0) provided made raw */ /* stty(0,&cookedmode); */ return; } /* End of cooktty */ rawtty() /* set terminal raw */ { if (cookedok == 0) { /* first time only */ /* gtty(0,&cookedmode); Save current mode so we can */ /* gtty(0,&rawmode); restore it later */ cookedok = 1; rawmode.sg_flags != (RAW|TANDEM); rawmode.sg_flags &= ~(ECHO|CRMOD); } /* stty(0,&rawmode); Put tty in raw mode */ return; } /* End of rawtty() */ /* end of tty cook/uncook routines */ /* * n e x t i n * * Timeouts are always accompanied by attempting to read * the line. Two situations are catered for: normally, * if a timeout can be set which cancels a hanging * read() call, then this is done; else if a test * can be made as to whether chars are available AND * a sleep() call is available, these are linked to * provide a timeout based on decrementing after * each sleep(). */ char nextin() /* read next char, checking time-flag */ /* return char (or 0 if timer expired) */ { char c; static char buff[2048]; static int count = 0, cmax = 0, ccnt = 0; long lcount; if (count == 0) cmax = count = read(0, buff, 2047); c = buff[cmax - (count--)]; if (debug > 2) { if (ccnt == 0) fprintf(dfp, "\n"); if (ccnt > 15) { fprintf(dfp," %x \n",((int)c)&0xff ); ccnt = 0; } else { fprintf(dfp," %x ",((int)c)&0xff ); ++ccnt; } } return(c); } /* end of nextin() */ timoset(sex) /* set timeout */ char sex; /* # of seconds */ { timflag = sex; /* signal(SIGALRM,timoex); alarm(timflag); */ return; } /* End of timoset() */ /* The routines which action and clear timeouts, timoex() and timocan() are not system-dependent; see above. */ /* * u n b u f f e r * * System-dependent action to do quick terminal writes * */ unbuffer() /* unbuffer output */ /* system-dependent action to write quickly to terminal */ { /* setbuf(stdout,0); UNbuffer output! */ return; } /* End of unbuffer() */ /* * w i l d n a m e * * Routine to retrieve Honeywell files using wildcards * */ wildname(line) char *line; { unsigned char *sn, *fsn; char fnamx[MOD4_NAME-1]; int type = 0; fsn = sn = star_name(line, "\0"); /* file in working dir */ filecount = 0; if (*sn == 0) return(0); /* no filenames given */ while (*sn != 0) { /* loop through star name list */ type = *sn; /* MOD400 file type */ sprintf(fnamx, "%s", ++sn); /* make file name into string */ switch(type) { /* only ship files of the cmd line type! */ case F_R: if (fileimage == BINARY) { filenames[filecount] = sn; filecount += 1; } break; case SEQ: case SVQ: if ((fsize(sn,1) != 0) && (fileimage == FOREIGN)) { filenames[filecount] = sn; filecount += 1; } if ((fsize(sn,1) == 0) && (fileimage == ASCII)) { filenames[filecount] = sn; filecount += 1; } break; case S_R: if (fileimage == ASCII) { filenames[filecount] = sn; filecount += 1; } break; default: break; } /* end switch; fall through if not ASCII/BINARY */ sn += strlen(fnamx)+1; /* point to next file name */ } /* end while */ free(fsn); /* star_name() uses the heap; give back the mem */ } /* end of wildname() */ /********************* END of FILE hd6ker.c **************************/