gregg@okstate.UUCP (03/08/85)
echo x - ckermi.mss part1 sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.mss X@comment[ -*-Text-*- ] X@Part(CKUNIX,root="KER:KUSER") X@string(-ckversion="@q<4.2>") X@define(exx=example,above 2,below 1) X@Chapter<UNIX KERMIT> X X@Begin<Description,Leftmargin +12,Indent -12,spread 0> X@i(Program:)@\Frank da Cruz, Bill Catchings, Jeff Damens, Columbia XUniversity; Herm Fischer, Litton Data Systems, Van Nuys CA; contributions by Xmany others. X X@i(Language:)@\C X X@i(Documentation:)@\Frank da Cruz, Columbia University; Herm XFischer, Litton Data Systems, Van Nuys CA. X X@i(Version:)@\@value(-ckversion) X X@i(Date: )@\March 1985 X@end<Description> X@Center(D R A F T) X X@begin(quotation) XNOTE -- This source for this Xdocumentation is written as input for the Scribe text formatter. XIt needs to become input for two text formatters - Scribe and Nroff, the Xformer for inclusion in the Kermit User Guide, and the latter for XUnix man pages. This might be done by defining formatting macros Xin M4, which generate the appropriate Scribe and Nroff commands for Xsectioning, itemization, description, etc. (Volunteers?) X@end(quotation) X XC-Kermit is a completely new implementation of Kermit, written modularly and Xtransportably in C. The protocol state transition table is written in X@i'wart', a (not proprietary) lex-like preprocessor for C. System-dependent Xprimitive functions are isolated into separately compiled modules so that the Xprogram should be easily portable among Unix systems and also to non-Unix Xsystems that have C compilers. X X@subheading<Unix Kermit Capabilities At A Glance:> X@begin<format,leftmargin +2,above 1,below 1> X@tabclear()@tabset(3.5inches,4.0inches) XLocal operation:@\Yes XLocal operation:@\Yes XRemote operation:@\Yes XLogin scripts:@\Yes XTransfer text files:@\Yes XTransfer binary files:@\Yes XWildcard send:@\Yes XFile transfer interruption:@\Yes XFilename collision avoidance:@\Yes XCan time out:@\Yes X8th-bit prefixing:@\Yes XRepeat count prefixing:@\Yes XAlternate block checks:@\Yes XTerminal emulation:@\Yes XCommunication settings:@\Yes XTransmit BREAK:@\Yes XSupport for dialout modems:@\Yes XIBM mainframe communication:@\Yes XTransaction logging:@\Yes XSession logging:@\Yes XDebug logging:@\Yes XPacket logging:@\Yes XAct as server:@\Yes XTalk to server:@\Yes XAdvanced server functions:@\Yes XLocal file management:@\Yes XCommand/Init files:@\Yes XUUCP and multiuser line locking:@\Yes XFile attributes:@\No XCommand macros:@\No XRaw file transmit:@\No X@end<format> X X@index(C-Kermit)@index(Unix Kermit) XC-Kermit provides traditional Unix command line operation as well as Xinteractive command prompting and execution. The command line options Xprovide access to a minimal subset of C-Kermit's capabilities; the Xinteractive command set is far richer. X XOn systems with dialout modems, C-Kermit can use command files and login Xscripts to essentially duplicate the file transfer functionality of uucp among Xheterogeneous operating systems, including by the use of scheduled (e.g. late Xnight) unattended operation. X X@section(The Unix File System) X XConsult your Unix manual for details about the file system under your Xversion of Unix. For the purposes of Kermit, several things are worth Xbriefly noting. Unix files generally have lowercase names. Unix Xdirectories are tree-@|structured. Directory levels are separated by X"@q(/)" characters. For example, X@example(/usr/foo/bar) Xdenotes the file @q(bar) in the directory @q(/usr/foo). Wildcard or X"meta" characters allow groups of files to be specified. "@q(*)" Xmatches any string; "@q(?)" matches any single character. X XWhen C-Kermit is invoked with files specified on the Unix command line, Xthe Unix shell (Bourne Shell, C-Shell, etc) expands meta characters, and Xin this case, a wider variety is available. For example, X@example(kermit -s ~/ck[x-z]*.[ch]) Xis expanded by the Berkeley C-Shell into a list of all the files in the Xuser's home directory (@q[~/]) that start with the characters "@q(ck)", Xfollowed by a single character @q(x), @q(y), or @q(z), followed by zero Xor more characters, followed by a dot, followed by one of the characters X@q(c) or @q(h). Internally, the C-Kermit program itself expands only Xthe @q("*") and @q("?") meta characters. X XUnix files are linear streams of 8-bit bytes. Text files consist of X7-bit ASCII characters, with the high bit off (0), and lines separated by Xthe Unix newline character, which is linefeed (LF, ASCII 10). This Xdistinguishes Unix text files from those on most other ASCII systems, in Xwhich lines are separated by a carriage-@|return linefeed sequence X(CRLF, ASCII 13 followed by ASCII 10). Binary files are likely to contain Xdata in the high bits of the file bytes, and are not treated in terms of Xlines. X XWhen transferring files, C-Kermit will convert between upper and lower Xcase filenames and between LF and CRLF line terminators automatically, Xunless told to do otherwise. When binary files must be transferred, the Xprogram must be instructed not to perform LF/CRLF conversion (@q[-i] on the Xcommand line or "set file type" interactively; see below). X X@section(Command Line Operation) X XThe C-Kermit command line syntax has been changed from that of earlier Xreleases of Unix Kermit to conform to the "Proposed Syntax Standards for XUnix System Commands" put forth by Kathy Hemenway and Helene Armitage of XAT&T Bell Laboratories in @ux(Unix/World), Vol.1, No.3, 1984. The rules that Xapply are: X X@begin(itemize,spread 0) XCommand names must be between 2 and 9 characters ("kermit" is 6). X XCommand names must include lower case letters and digits only. X XAn option name is a single character. X XOptions are delimited by '@q(-)'. X XOptions with no arguments may be grouped (bundled) behind one delimiter. X XOption-arguments cannot be optional. X XArguments immediately follow options, separated by whitespace. X XThe order of options does not matter. X X'@q(-)' preceded and followed by whitespace means standard input. X@end(itemize) XA group of bundled options may end with an option that has an argument. X XThe following notation is used in command descriptions: X@begin(description,leftmargin +8,indent -8) X@i(fn)@\A Unix file specification, possibly containing the "wildcard" Xcharacters '@q[*]' or '@q[?]' ('@q[*]' matches all character strings, '@q[?]' Xmatches any single character). X X@i(fn1)@\A Unix file specification which may not contain '@q[*]' or '@q[?]'. X X@i(rfn)@\A remote file specification in the remote system's own syntax, which Xmay denote a single file or a group of files. X X@i(rfn1)@\A remote file specification which should denote only a single file. X X@i(n)@\A decimal number between 0 and 94. X X@i(c)@\A decimal number between 0 and 127 representing the value of an XASCII character. X X@i(cc)@\A decimal number between 0 and 31, or else exactly 127, Xrepresenting the value of an ASCII control character. X X@q([ ])@\Any field in square braces is optional. X X@q({x,y,z})@\Alternatives are listed in curly braces. X@end(description) X XC-Kermit command line options may specify either actions or settings. If XC-Kermit is invoked with a command line that specifies no actions, then it Xwill issue a prompt and begin interactive dialog. XAction options specify either protocol transactions or terminal connection. X X@begin<description,leftmargin +8,indent -8> X@q(-s )@i(fn)@\Send the specified file or files. If @i(fn) contains Xwildcard (meta) characters, the Unix shell expands it into a list. If @i(fn) Xis '@q[-]' then kermit sends from standard input, which must Xcome from a file: X@example(kermit -s - < foo.bar) Xor a parallel process: X@example(ls -l | kermit -s -) XYou cannot use this mechanism to send Xterminal typein. If you want to send a file whose name is "-" Xyou can precede it with a path name, as in X@example(kermit -s ./-) X X@q(-r)@\Receive a file or files. Wait passively for files to arrive. X X@q(-k)@\Receive (passively) a file or files, sending them to standard Xoutput. This option can be used in several ways: X@begin(description,leftmargin +4,indent -4) X@q(kermit -k)@\Displays the incoming files on your screen; to be used only Xin "local mode" (see below). X X@q(kermit -k > )@i(fn1)@\Sends the incoming file or files to the named file, X@i(fn1). If more than one file arrives, all are concatenated together Xinto the single file @i(fn1). X X@q(kermit -k | command)@\Pipes the incoming data (single or multiple Xfiles) to the indicated command, as in X@example'kermit -k | sort > sorted.stuff' X@end(description) X X@q(-a )@i(fn1)@\If you have specified a file transfer option, you may specify Xan alternate name for a single file with the @q(-a) option. For example, X@example'kermit -s foo -a bar' Xsends the file @q(foo) telling the receiver that its name is @q(bar). XIf more than one file arrives or is sent, only the first file is Xaffected by the @q(-a) option: X@example'kermit -ra baz' Xstores the first incoming file under the name @q(baz). X X@q(-x)@\Begin server operation. May be used in either local or remote mode. X@end(description) X XBefore proceeding, a few words about remote and local operation are Xnecessary. C-Kermit is "local" if it is running on PC or workstation that Xyou are using directly, or if it is running on a multiuser system and Xtransferring files over an external communication line -- not your job's Xcontrolling terminal or console. C-Kermit is remote if it is running on a Xmultiuser system and transferring files over its own controlling terminal's Xcommunication line, connected to your PC or workstation. X XIf you are running C-Kermit on a PC, it is in local mode by default, Xwith the "back port" designated for file transfer and terminal connection. XIf you are running C-Kermit on a multiuser (timesharing) system, it is Xin remote mode unless you explicitly point it at an external line for Xfile transfer or terminal connection. The following command sets XC-Kermit's "mode": X X@begin(description,leftmargin +8,indent -8) X@q(-l )@i(dev)@\Line -- Specify a terminal line to use for file Xtransfer and terminal connection, as in X@example'kermit -l /dev/ttyi5' X@end(description) X XWhen an external line is being used, you might also need some additional Xoptions for successful communication with the remote system: X X@begin(description,leftmargin +8,indent -8) X@q(-b )@i(n)@\Baud -- Specify the baud rate for the line given in the X@q(-l) option, as in X@example'kermit -l /dev/ttyi5 -b 9600' XThis option should always be included with the @q(-l) option, since the Xspeed of an external line is not necessarily what you expect. X X@q(-p )@i(x)@\Parity -- e,o,m,s,n (even, odd, mark, space, or none). If parity Xis other than none, then the 8th-bit prefixing mechanism will be Xused for transferring 8-bit binary data, provided the opposite XKermit agrees. The default parity is none. X X@q(-t)@\Specifies half duplex, line turnaround with XON as the handshake Xcharacter. X@end(description) X XThe following commands may be used only with a C-Kermit which is local -- Xeither by default or else because the -l option has been specified. X X@begin(description,leftmargin +8,indent -8) X@q(-g )@i(rfn)@\Actively request a remote server to send the named file Xor files; @i(rfn) is a file specification in the remote host's own syntax. If X@i(fn) happens to contain any special shell characters, like '@q(*)', Xthese must be quoted, as in X@example'kermit -g x\*.\?' X X@q(-f)@\Send a 'finish' command to a remote server. X X@q(-c)@\Establish a terminal connection over the specified or default Xcommunication line, before any protocol transaction takes place. XGet back to the local system by typing the escape character X(normally Control-Backslash) followed by the letter 'c'. X X@q(-n)@\Like @q(-c), but after a protocol transaction takes place; X@q(-c) and @q(-n) may both be used in the same command. The use of @q(-n) Xand @q(-c) is illustrated below. X@end(description) XOn a timesharing system, the @q(-l) and @q(-b) options will also have to Xbe included with the @q(-r), @q(-k), or @q(-s) options if the other XKermit is on a remote system. X XIf C-Kermit is in local mode, the screen (stdout) is continously updated to Xshow the progress of the file transer. A dot is printed for every four data Xpackets, other packets are shown by type (e.g. '@q(S)' for Send-Init), X'@q(T)' is printed when there's a timeout, and '@q(%)' for each Xretransmission. In addition, you may type (to stdin) certain "interrupt" Xcommands during file transfer: X@begin(description,leftmargin +16,indent -12,spread 0) XControl-F:@\Interrupt the current File, and go on to the next (if any). X XControl-B:@\Interrupt the entire Batch of files, terminate the transaction. X XControl-R:@\Resend the current packet X XControl-A:@\Display a status report for the current transaction. X@end(description) XThese interrupt characters differ from the ones used in other Kermit Ximplementations to avoid conflict with Unix shell interrupt characters. XWith System III and System V implementations of Unix, interrupt commands Xmust be preceeded by the escape character (e.g. control-@q[\]). X XSeveral other command-line options are provided: X X@begin(description,leftmargin +8,indent -8) X@q(-i)@\Specifies that files should be sent or received exactly "as is" Xwith no conversions. This option is necessary for transmitting Xbinary files. It may also be used to slightly boost efficiency Xin Unix-to-Unix transfers of text files by eliminating CRLF/newline Xconversion. X X@q(-w)@\Write-Protect -- Avoid filename collisions for incoming files. X X@q(-q)@\Quiet -- Suppress screen update during file transfer, for instance Xto allow a file transfer to proceed in the background. X X@q(-d)@\Debug -- Record debugging information in the file @q(debug.log) in Xthe current directory. Use this option if you believe the program Xis misbehaving, and show the resulting log to your local Xkermit maintainer. X X@q(-h)@\Help -- Display a brief synopsis of the command line options. X@end(description) XThe command line may contain no more than one protocol action option. X XFiles are sent with their own names, except that lowercase letters are Xraised to upper, pathnames are stripped off, tilde ('@q[~]') characters Xchanged to '@q(X)', and if the file name begins with a period, an X'@q(X)' is inserted before it. Incoming files are stored under their Xown names except that uppercase letters are lowered, and, if @q(-w) was Xspecified, a "generation number" is appended to the name if it has the Xsame name as an existing file which would otherwise be overwritten. If Xthe @q(-a) option is included, then the same rules apply to its Xargument. The file transfer display shows any transformations performed Xupon filenames. X XDuring transmission, files are encoded as follows: X@begin(itemize) XControl characters are converted to prefixed printables. X XSequences of repeated characters are collapsed via repeat counts, if Xthe other Kermit is also capable of repeated-character compression. X XIf parity is being used on the communication line, data characters with Xthe 8th (parity) bit on are specially prefixed, provided the other Kermit Xis capable of 8th-bit prefixing (if not, 8-bit binary files cannot be Xsuccessfully transferred). X XConversion is done between Unix newlines and carriage-return-linefeed Xsequences unless the @q(-i) option was specified. X@end(itemize) X X@subheading(Command Line Examples:) X X@example(kermit -l /dev/ttyi5 -b 1200 -cn -r) XThis command connects you to the system on the other end of ttyi5 at X1200 baud, where you presumably log in and run Kermit with a 'send' Xcommand. After you escape back, C-Kermit waits for a file (or files) to Xarrive. When the file transfer is completed, you are again connected to Xthe remote system so that you can logout. X X@example(kermit -l /dev/ttyi4 -b 1800 -cntp m -r -a foo) XThis command is like the preceding one, except the remote system in this Xcase uses half duplex communication with mark parity. The first file Xthat arrives is stored under the name @q(foo). X X@exx(kermit -l /dev/ttyi6 -b 9600 -c | tek) XThis example uses Kermit to connect your terminal to the system at the Xother end of ttyi6. The C-Kermit terminal connection does not Xprovide any particular terminal emulation, so C-Kermit's standard i/o is Xpiped through a (hypothetical) program called tek, which performs (say) XTektronix emulation. X X@exx(kermit -l /dev/ttyi6 -b 9600 -nf) XThis command would be used to shut down a remote server and then connect Xto the remote system, in order to log out or to make further use of it. XThe @q(-n) option is invoked @i(after) @q(-f) (@q[-c] would have been invoked Xbefore). X X@exx(kermit -l /dev/ttyi6 -b 9600 -qg foo.\* &) XThis command causes C-Kermit to be invoked in the background, getting a group Xof files from a remote server (note the quoting of the '@q[*]' character). No Xdisplay occurs on the screen, and the keyboard is not sampled for Xinterruption commands. This allows other work to be done while file Xtransfers proceed in the background. X X@exx(kermit -l /dev/ttyi6 -b 9600 -g foo.\* > foo.log < /dev/null &) XThis command is like the previous one, except the file transfer display has Xbeen redirected to the file @q(foo.log). Standard input is also redirected, to Xprevent C-Kermit from sampling it for interruption commands. X X@exx(kermit -iwx) XThis command starts up C-Kermit as a server. Files are transmitted with Xno newline/@|carriage-@|return-@|linefeed conversion; the @q(-i) option is Xnecessary for binary file transfer and useful for Unix-@|to-@|Unix transfers. XIncoming files that have the same names as existing files are given new, unique Xnames. X X@exx(kermit -l /dev/ttyi6 -b 9600) XThis command sets the communication line and speed. Since no action is Xspecified, C-Kermit issues a prompt and enters an interactive dialog with Xyou. Any settings given on the command line remain in force during the Xdialog, unless explicitly changed. X X@exx(kermit) XThis command starts up Kermit interactively with all default settings. X XA final example shows how Unix Kermit might be used to send an entire directory Xtree from one Unix system to another, using the tar program as Kermit's Xstandard input and output. On the orginating system, in this case the remote, Xtype (for instance):@label(-uxtar) X X@exx(tar cf - /usr/fdc | kermit -is -) XThis causes tar to send the directory @q(/usr/fdc) (and all its files and all Xits subdirectories and all their files...) to standard output instead of to a Xtape; kermit receives this as standard input and sends it as a binary file. XOn the receiving system, in this case the local one, type (for instance): X X@exx(kermit -il /dev/ttyi5 -b 9600 -k | tar xf -) XKermit receives the tar archive, and sends it via standard output to its own Xcopy of tar, which extracts from it a replica of the original directory tree. X X@subheading(Exit Status Codes:) X XKermit returns an exit status of zero, except when a fatal error is Xencountered, where the exit status is set to one. With background Xoperation (e.g., '@q(&)' on invoking command line), driven by scripted Xinteractive commands (redirected standard input and/or take files), Xany failed interactive command (such as failed dial or script attempt) Xcauses the fatal error exit. X X X@section(Interactive Operation) X XC-Kermit's interactive command prompt is "@q(C-Kermit>)". In response to this Xprompt, you may type any valid command. C-Kermit executes the command and Xthen prompts you for another command. The process continues until you Xinstruct the program to terminate. X XCommands begin with a keyword, normally an English verb, such as "send". XYou may omit trailing characters from any keyword, so long as you specify Xsufficient characters to distinguish it from any other keyword valid in that Xfield. Certain commonly-used keywords (such as "send", "receive", "connect") Xhave special non-unique abbreviations ("s" for "send", "r" for "receive", X"c" for "connect"). X XCertain characters have special functions in interactive commands: X@Begin(Description,leftmargin +8,indent -4) X@q(?)@\Question mark, typed at any point in a command, will produce a Xmessage explaining what is possible or expected at that point. Depending on Xthe context, the message may be a brief phrase, a menu of keywords, or a list Xof files. X X@q(ESC)@\(The Escape or Altmode key) -- Request completion of the current Xkeyword or filename, or insertion of a default value. The result will be a Xbeep if the requested operation fails. X X@q(DEL)@\(The Delete or Rubout key) -- Delete the previous character from the Xcommand. You may also use BS (Backspace, Control-H) for this function. X X@q(^W)@\(Control-W) -- Erase the rightmost word from the command line. X X@q(^U)@\(Control-U) -- Erase the entire command. X X@q(^R)@\(Control-R) -- Redisplay the current command. X X@q(SP)@\(Space) -- Delimits fields (keywords, filenames, numbers) within Xa command. HT (Horizontal Tab) may also be used for this purpose. X X@q(CR)@\(Carriage Return) -- Enters the command for execution. LF (Linefeed) Xor FF (formfeed) may also be used for this purpose. X X@q(\)@\(Backslash) -- Enter any of the above characters into the command, Xliterally. To enter a backslash, type two backslashes in a row (@q[\\]). X@End(Description) XYou may type the editing characters (@q[DEL], @q[^W], etc) repeatedly, to Xdelete all the way back to the prompt. No action will be performed until the Xcommand is entered by typing carriage return, linefeed, or formfeed. If you Xmake any mistakes, you will receive an informative error message and a new Xprompt -- make liberal use of '@q[?]' and ESC to feel your way through the Xcommands. One important command is "help" -- you should use it the first time Xyou run C-Kermit. X XInteractive C-Kermit accepts commands from files as well as from the Xkeyboard. When you enter interactive mode, C-Kermit looks for the file X@q(.kermrc) in your home or current directory (first it looks in the home Xdirectory, then in the current one) and executes any commands it finds there. XThese commands must be in interactive format, not Unix command-line format. XA "take" command is also provided for use at any time during an interactive Xsession. Command files may be nested to any reasonable depth. X XHere is a brief list of C-Kermit interactive commands: X@begin(format,spread 0) X@tabclear()@tabset(1.5inches,2.0inches,2.5inches) X@>!@\ Execute a Unix shell command. X@>bye@\ Terminate and log out a remote Kermit server. X@>close@\ Close a log file. X@>connect@\ Establish a terminal connection to a remote system. X@>cwd@\ Change Working Directory. X@>dial@\ Dial a telephone number. X@>directory@\ Display a directory listing. X@>echo@\ Display arguments literally. X@>exit@\ Exit from the program, closing any open logs. X@>finish@\ Instruct a remote Kermit server to exit, but not log out. X@>get@\ Get files from a remote Kermit server. X@>help@\ Display a help message for a given command. X@>log@\ Open a log file -- debugging, packet, session, transaction. X@>quit@\ Same as 'exit'. X@>receive@\ Passively wait for files to arrive. X@>remote@\ Issue file management commands to a remote Kermit server. X@>script@\ Execute a login script with a remote system. X@>send@\ Send files. X@>server@\ Begin server operation. X@>set@\ Set various parameters. X@>show@\ Display values of 'set' parameters. X@>space@\ Display current disk space usage. X@>statistics@\ Display statistics about most recent transaction. X@>take@\ Execute commands from a file. X@end(format) X XThe 'set' parameters are: X@begin(format,spread 0) X@tabclear()@tabset(1.5inches,2.0inches,2.5inches) X@>block-check@\ Level of packet error detection. X@>delay@\ How long to wait before sending first packet. X@>duplex@\ Specify which side echoes during 'connect'. X@>end-of-packet@\ Terminator for outbound packets. X@>escape-character@\ Character to prefix "escape commands" during 'connect'. X@>file@\ Set various file parameters. X@>flow-control@\ Communication line full-duplex flow control. X@>handshake@\ Communication line half-duplex turnaround character. X@>line@\ Communication line device name. X@>modem-dialer@\ Type of modem-dialer on communication line. X@>packet-length@\ Maximum length for packets. X@>pad-character@\ Character to use for inter-packet padding. X@>padding@\ How much inter-packet padding to use. X@>parity@\ Communication line character parity. X@>prompt@\ Change the C-Kermit program's prompt. X@>speed@\ Communication line speed. X@>start-of-packet@\ Control character to mark beginning of packets. X@>timeout@\ Timer interval to detect lost packets. X@end(format) X XThe 'remote' commands are: X@begin(format,spread 0) X@tabclear()@tabset(1.5inches,2.0inches,2.5inches) X@>cwd@\ Change remote working directory. X@>delete@\ Delete remote files. X@>directory@\ Display a listing of remote file names. X@>help@\ Request help from a remote server. X@>host@\ Issue a command to the remote host in its own command language. X@>space@\ Display current disk space usage on remote system. X@>type@\ Display a remote file on your screen. X@>who@\ Display who's logged in, or get information about a user. X@end(format) X XMost of these commands are described adequately in the Kermit User Guide. XSpecial aspects of certain Unix Kermit commands are described below. X X@heading<The 'send' command> X XSyntax: @q<send >@i(fn)@q<@ @ - >@i<or>@q< -@ @ >@q<send >@i(fn1)@q< >@i<rfn1> X XSend the file or files denoted by fn to the other Kermit, which should be Xrunning as a server, or which should be given the 'receive' command. Each Xfile is sent under its own name (as described above, or as Xspecified by the 'set file names' command). If the second form is used, Xi.e. with @i(fn1) denoting a single Unix file, @i(rfn1) may be specified as a Xname to send it under. The 'send' command may be abbreviated to 's', even Xthough 's' is not a unique abbreviation for a top-level C-Kermit command. X XThe wildcard (meta) characters '@q[*]' and '@q[?]' are accepted in @i(fn). If X'@q[?]' is to be included, it must be prefixed by '@q[\]' to override its Xnormal function of providing help. '@q[*]' matches any string, '@q[?]' matches Xany single character. Other notations for file groups, like '@q([a-z]og)', are Xnot available in interactive commands (though of course they are available on Xthe command line). When @i(fn) contains '@q[*]' or '@q[?]' characters, there Xis a limit to the number of files that can be matched, which varies from system Xto system. If you get the message "Too many files match" then you'll have to Xmake a more judicious selection. If @i(fn) was of the form X@example(usr/longname/anotherlongname/*) Xthen C-Kermit's string space will fill up rapidly -- try doing a cwd (see Xbelow) to the path in question and reissuing the command. X X@i<Note> -- C-Kermit sends only from the current or specified directory. XIt does not traverse directory trees. If the source directory contains Xsubdirectories, they will be skipped. Conversely, C-Kermit does not create Xdirectories when receiving files. If you have a need to do this, you can Xpipe tar through C-Kermit, as shown in the example on page @pageref(-uxtar), Xor under System III/V Unix you can use cpio. X X@i<Another Note> -- C-Kermit does not skip over "invisible" files that match Xthe file specification; Unix systems usually treat files whose names start Xwith a dot (like @q(.login), @q(.cshrc), and @q(.kermrc)) as invisible. X X@heading<The 'receive' command> X XSyntax: @q<receive@ @ - >@i<or>@q< -@ @ receive >@i<fn1> X XPassively wait for files to arrive from the other Kermit, which must be given Xthe 'send' command -- the 'receive' command does not work in conjunction with a Xserver (use 'get' for that). If @i(fn1) is specified, store the first incoming Xfile under that name. The 'receive' command may be abbreviated to 'r'. X X X@heading<The 'get' command:> X XSyntax:@q< get >@i<rfn> X@begin(example) X @i<or>: get X @i(rfn) X @i(fn1) X@end(example) XRequest a remote Kermit server to send the named file or files. Since a Xremote file specification (or list) might contain spaces, which normally Xdelimit fields of a C-Kermit command, an alternate form of the command is Xprovided to allow the inbound file to be given a new name: type 'get' alone Xon a line, and you will be prompted separately for the remote and local Xfile specifications, for example X@Begin(Example) XC-Kermit>@ux(get) X Remote file specification: @ux(foo) X Local name to store it under: @ux(bar) X@End(Example) XAs with 'receive', if more than one file arrives as a result of the 'get' Xcommand, only the first will be stored under the alternate name given by X@i(fn1); the remaining files will be stored under their own names if possible. XIf a '@q[?]' is to be included in the remote file specification, you must Xprefix it with '@q[\]' to suppress its normal function of providing help. X X@heading(The 'server' command:) X XThe 'server' command places C-Kermit in "server mode" on the currently selected Xcommunication line. All further commands must arrive as valid Kermit packets Xfrom the Kermit on the other end of the line. The Unix Kermit server can Xrespond to the following commands: X@begin(format,spread 0,above 1,below 1) X@tabclear()@tabset(2.25inches) X@u<Command>@\@ux<Server Response> X get@\ Sends files X send@\ Receives files X bye@\ Attempts to log itself out X finish@\ Exits to level from which it was invoked X remote directory@\ Sends directory lising X remote delete@\ Removes files X remote cwd@\ Changes working directory X remote type@\ Sends files to your screen X remote space@\ Reports about its disk usage X remote who@\ Shows who's logged in X remote host@\ Executes a Unix shell command X remote help@\ Lists these capabilities X@end(format) XNote that the Unix Kermit server cannot always respond to a BYE command. XIt will attempt to do so using "@q<kill(0,9)>", but this will not work Xon all systems or under all conditions. For instance, the C-Shell Xchanges your process group, so that the process id of 0 does not refer Xto what you might expect. X XIf the Kermit server is directed at an external line (i.e. it is in X"local mode") then the console may be used for other work if you have X'set file display off'; normally the program expects the Xconsole to be used to observe file transfers and enter status queries or Xinterruption commands. The way to get C-Kermit into background operation from Xinteractive command level varies from system to system (e.g. on Berkeley Unix Xyou would halt the program with @q(^Z) and then use the C-Shell 'bg' command to Xcontinue it in the background). The more common method Xis to invoke the program with the desired command line arguments, including X"@q(-q)", and with a terminating "@q(&)". X XWhen the Unix Kermit server is given a 'remote host' command, it executes it Xusing the shell invoked upon login to the remote system, e.g. the Bourne shell Xor the Berkeley C-Shell. (Note -- this is in distinction to the local "@q<!>" Xshell escape, which always uses the Bourne shell; see below). X X@Heading(The 'remote', 'bye', and 'finish' commands:) X XC-Kermit may itself request services from a remote Kermit server. In Xaddition to the 'send' and 'get' commands, the following may also be used: X X@begin(description,leftmargin +8,indent -4) Xremote cwd [@i(directory)]@\If the optional remote directory specification is Xincluded, you will be prompted on a separate line for a password, which will Xnot echo as you type it. X@end(description) X@begin(description,leftmargin +28, indent -24,spread 0,above 1) Xremote delete rfn@\delete remote file or files. X Xremote directory [@i(rfn)]@\directory listing of remote files. X Xremote host @i(command)@\command in remote host's own command language. X Xremote space@\disk usage report from remote host. X Xremote type [@i(rfn)]@\display remote file or files on the screen. X Xremote who [@i(user)]@\display information about who's logged in. X Xremote help@\display remote server's capabilities. X@end(description) X@begin(description,leftmargin +8,indent -4) Xbye @i(and) finish:@\When connected to a remote Kermit server, these commands Xcause the remote server to terminate; 'finish' returns it to Kermit or system Xcommand level (depending on the implementation or how the program was invoked); X'bye' also requests it to log itself out. X@end(description) X@heading(The 'log' and 'close' commands:) X XSyntax: @q<log {debugging, packets, session, transactions} >[ @i(fn1) ] X XC-Kermit's progress may be logged in various ways. The 'log' command Xopens a log, the 'close' command closes it. In addition, all open logs Xare closed by the 'exit' and 'quit' commands. A name may be specified for Xa log file; if the name is omitted, the file is created with a default Xname as shown below. X X@begin(description,leftmargin +4,indent -4) Xlog debugging@\This produces a voluminous log of the internal workings of XC-Kermit, of use to Kermit developers or maintainers in tracking down suspected Xbugs in the C-Kermit program. Use of this feature dramatically slows down the XKermit protocol. Default name: @q(debug.log). X Xlog packets@\This produces a record of all the packets that go in and out of Xthe communication port. This log is of use to Kermit maintainers who are Xtracking down protocol problems in either C-Kermit or any Kermit that XC-Kermit is connected to. Default name: @q(packet.log). X Xlog session@\This log will contain a copy of everything you see on your screen Xduring the 'connect' command, except for local messages or interaction with Xlocal escape commands. Default name: @q(session.log). X Xlog transactions@\The transaction log is a record of all the files that were Xsent or received while transaction logging was in effect. It includes time Xstamps and statistics, filename transformations, and records of any Xerrors that may have occurred. The transaction log allows you to have Xlong unattended file transfer sessions without fear of missing some Xvital screen message. Default name: @q(transaction.log). X@end(description) XThe 'close' command explicitly closes a log, e.g. 'close debug'. X X@Heading(Local File Management Commands:) X XUnix Kermit allows some degree of local file management from interactive Xcommand level: X@begin(description,leftmargin +4,indent -4) Xdirectory [@i(fn)]@\ XDisplays a listing of the names, modes, sizes, and dates of files Xmatching @i(fn) (which defaults to '@q[*]'). Equivalent to '@q(ls -l)'. X Xcwd [directory-name]@\ XChanges Kermit's working directory to the one given, or to the your Xdefault directory if the directory name is omitted. Equivalent to 'cd'. X Xspace@\ XDisplay information about disk space and/or quota in the current Xdirectory and device. X X@q(! )@i(command)@\ XThe command is executed by the Unix shell. Use this for all other Xfile management commands. This command has certain peculiarities: X@begin(itemize,spread 0) XThe Bourne shell is used. X XAt least one space must separate the '!' from the shell command. X XA 'cd' command executed in this manner will have no effect -- use the XC-Kermit 'cwd' command instead. X@end(itemize) X@end(description) X X@heading(The 'set' and 'show' Commands:) X XSince Kermit is designed to allow diverse systems to communicate, it is Xoften necessary to issue special instructions to allow the program to adapt Xto peculiarities of the another system or the communication path. These Xinstructions are accomplished by the 'set' command. The 'show' command may Xbe used to display current settings. Here is a brief synopsis of settings Xavailable in the current release of C-Kermit: X X@begin(description,leftmargin +4,indent -4) Xblock-check {1, 2, 3}@\ Determines the level of per-packet error detection. X"1" is a single-@|character 6-bit checksum, folded to include the values of all Xbits from each character. "2" is a 2-character, 12-bit checksum. "3" is a X3-character, 16-bit cyclic redundancy check (CRC). The higher the block check, Xthe better the error detection and correction and the higher the resulting Xoverhead. Type 1 is most commonly used; it is supported by all Kermit Ximplementations, and it has proven adequate in most circumstances. Types 2 or X3 would be used to advantage when transferring 8-bit binary files over noisy Xlines. X Xdelay @i(n)@\How many seconds to wait before sending the first packet after a X'send' command. Used in remote mode to give you time to escape back to your !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckermi.mss part 2 sed '1,$s/^X//' <<\!FUNKY!STUFF! >> ckermi.mss Xlocal Kermit and issue a 'receive' command. Normally 5 seconds. X Xduplex {full, half}@\For use during 'connect'. Specifies which side is doing Xthe echoing; 'full' means the other side, 'half' means C-Kermit must echo Xtypein itself. X Xend-of-packet @i(cc)@\Specifies the control character needed by the other XKermit to recognize the end of a packet. C-Kermit sends this character at the Xend of each packet. Normally 13 (carriage return), which most Kermit Ximplementations require. Other Kermits require no terminator at all, still Xothers may require a different terminator, like linefeed (10). X Xescape-character @i(cc)@\For use during 'connect' to get C-Kermit's attention. XThe escape character acts as a prefix to an 'escape command', for instance to Xclose the connection and return to C-Kermit or Unix command level. XThe normal escape character is Control-Backslash (28). XThe escape character is also used in System III/V implementations, Xto prefix interrupt commands during file transfers. X Xfile {display, names, type, warning}@\ XEstablish various file-related parameters: X@begin(description,leftmargin +4,indent -4) Xdisplay {on, off}@\Normally 'on'; when in local mode, display progress of file Xtransfers on the screen (stdout), and listen to the keyboard (stdin) Xfor interruptions. If off (-q on command line) none of this is Xdone, and the file transfer may proceed in the background oblivious Xto any other work concurrently done at the console terminal. X Xnames {converted, literal}@\ XNormally converted, which mean that outbound filenames have path Xspecifications stripped, lowercase letters raised to upper, Xtildes and extra periods changed to X's, and an X inserted in Xfront of any name that starts with period. Incoming files have Xuppercase letters lowered. Literal means that none of these Xconversions are done; therefore, any directory path appearing in a Xreceived file specification must exist and be write-accessible. XWhen literal naming is being used, the sender should not use path Xnames in the file specification unless the same path exists on the Xtarget system and is writable. X Xtype {binary, text}@\Normally text, which means that conversion is done between XUnix newline characters and the carriage-@|return/@|linefeed sequences Xrequired by the canonical Kermit file transmission format, and in Xcommon use on non-@|Unix systems. Binary means to transmit file Xcontents without conversion. Binary ('@q(-i)' in command line notation) Xis necessary for binary files, and desirable in all Unix-@|to-@|Unix Xtransactions to cut down on overhead. X Xwarning {on, off}@\Normally off, which means that incoming files will silently Xoverwrite existing files of the same name. When on ('@q(-w)' on command line) XKermit will check if an arriving file would overwrite an existing file; if so, Xit will construct a new name for the arriving file, of the form @q(foo~)@i(n), Xwhere foo is the name they share and @i(n) is a "generation number"; if @i(foo) Xexists, then the new file will be called @q(foo~1). If @q(foo) and @q(foo~1) Xexist, the new file will be @q(foo~2), and so on. X@end(description) X Xflow-control {none, xon/xoff}@\Normally xon/xoff for full duplex flow control. XShould be set to 'none' if the other system cannot do xon/xoff flow control. X Xhandshake {xon, xoff, cr, lf, bell, esc, none}@\ XNormally none. Otherwise, half-duplex communication line turnaround Xhandshaking is done, which means Unix Kermit will not reply to a packet Xuntil it has received the indicated handshake character or has timed out Xwaiting for it. X Xline [device-name]@\ XThe device name for the communication line to be used for file transfer Xand terminal connection, e.g. @q(/dev/ttyi3). If you specify a device name, XKermit will be in local mode, and you should remember to issue any other Xnecessary 'set' commands, such as 'set speed'. If you omit the device Xname, Kermit will revert to its default mode of operation. X Xmodem-dialer {direct, hayes, ventel}@\ The type of modem dialer on the Xcommunication line. "Direct" indicates either there is no dialout modem, or Xthat if the line requires carrier detection to open, then 'set line' will hang Xwaiting for an incoming call. "Hayes" and "Ventel" indicate that the Xsubsequent 'set line' (or the -l argument) will prepare for a subsequent 'dial' Xcommand for Hayes and Ventel dialers, respectively. X Xpacket-length @i(n)@\Specify the maximum packet length to use. Normally 90. XShorter packet lengths can be useful on noisy lines, or with systems or front Xends or networks that have small buffers. The shorter the packet, the higher Xthe overhead, but the lower the chance of a packet being corrupted by noise, Xand the less time to retransmit corrupted packets. X Xpad-character @i(cc)@\C-Kermit normally does not need to have incoming packets Xpreceded with pad characters. This command allows C-Kermit to request the Xother Kermit to use cc as a pad character. Default cc is NUL, ASCII 0. X Xpadding @i(n)@\How many pad characters to ask for, normally 0. X Xparity {even, odd, mark, space, none}@\Specify character parity for use in Xpackets and terminal connection, normally none. If other than none, C-Kermit Xwill seek to use the 8th-bit prefixing mechanism for transferring 8-bit binary Xdata, which can be used successfully only if the other Kermit agrees; if not, X8-bit binary data cannot be successfully transferred. X Xprompt [string]@\The given string will be substituted for "@q(C-Kermit)>" as Xthis program's prompt. If the string is omitted, the prompt will revert to X"@q(C-Kermit>)". X Xspeed {0, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 9600}@\The baud rate for Xthe external communication line. This command cannot be used to change the Xspeed of your own console terminal. Many Unix systems are set up in such a way Xthat you must give this command after a 'set line' command before you can use Xthe line. X Xstart-of-packet @i(cc)@\The Kermit packet prefix is Control-A (1). The only Xreasons it should ever be changed would be: Some piece of equipment somewhere Xbetween the two Kermit programs will not pass through a Control-A; or, some Xpiece of of equipment similarly placed is echoing its input. In the latter Xcase, the recipient of such an echo can change the packet prefix for outbound Xpackets to be different from that of arriving packets, so that the echoed Xpackets will be ignored. The opposite Kermit must also be told to change the Xprefix for its inbound packets. Unix Kermit presently can be told to change Xonly its outbound packet prefix. X Xtimeout @i(n)@\Normally, each Kermit partner sets its packet timeout interval Xbased on what the opposite Kermit requests. This command allows you to Xoverride the normal procedure and specify a timeout interval. If you specify X0, then no timeouts will occur, and Unix Kermit will wait forever for expected Xpackets to arrive. X@end(description) X X@heading(The 'show' Command:) X XSyntax: @q<show {parameters, versions}> X XThe show command displays the values of all the 'set' parameters described Xabove. If you type 'show versions', then C-Kermit will display the version Xnumbers and dates of all its internal modules. You should use the 'show Xversions' command to ascertain the vintage of your Kermit program before Xreporting problems to Kermit maintainers. X X@heading(The 'statistics' Command:) X XThe statistics command displays information about the most recent Kermit Xprotocol transaction, including file and communication line i/o, as well Xas what encoding options were in effect (such as 8th-bit prefixing, Xrepeat-@|count compression). X X@heading(The 'take' and 'echo' Commands:) X XSyntax: @q<take >@i<fn1> X XThe 'take' command instructs C-Kermit to execute commands from the named Xfile. The file may contain any interactive C-Kermit commands, including X'take'; command files may be nested to any reasonable depth. The 'echo' Xcommand may be used within command files to issue greetings, announce Xprogress, etc. X XCommand files are in exactly the same syntax as interactive commands. XNote that this implies that if you want to include special characters like Xquestion mark or backslash that you would have to quote with backslash when Xtyping interactive commands, you must quote these characters the same way Xin command files. X XCommand files may be used in lieu of command macros, which have not been Ximplemented in this version of C-Kermit. For instance, if you commonly Xconnect to a system called 'B' that is connected to ttyh7 at 4800 baud, Xyou could create a file called @q(b) containing the commands X@begin(example) Xset line /dev/ttyh7 Xset speed 4800 Xecho Connecting to System B... Xconnect X@end(example) Xand then simply type 'take b' (or 't b' since no other commands begin with Xthe letter 't') whenever you wished to connect to system B. X XFor connecting to IBM mainframes, a number of 'set' commands are required; Xthese, too, are conveniently collected into a 'take' file like this one: X@begin(example) Xset speed 1200 Xset parity mark Xset handshake xon Xset flow-control none Xset duplex half X@end(example) X XAn implicit 'take' command is executed upon your @q(.kermrc) file upon XC-Kermit's initial entry into interactive dialog. The @q(.kermrc) file should Xcontain 'set' or other commands you want to be in effect at all times. XFor instance, you might want override the default action when incoming files Xhave the same names as existing files -- in that case, put the command X@example(set file warning on) Xin your @q(.kermrc) file. X XCommands executed from take files are not echoed at the terminal. If you Xwant to see the commands as well as their output, you could feed the Xcommand file to C-Kermit via redirected stdin, as in X@example('kermit < cmdfile') XErrors encountered during execution of take files (such as failure to complete Xdial or script operations) cause termination of the current take file, popping Xto the take file that invoked it, or to interactive level. When kermit is Xexecuted in the background, errors during execution of a take file are fatal. X X@heading(The 'connect' Command:) X XThe connect command links your terminal to another computer as if it were Xa local terminal to that computer, through the device specified in the most Xrecent 'set line' command, or through the default device if your system Xis a PC or workstation. All characters you type at your keyboard Xare sent out the communication line, all characters arriving at the Xcommunication port are displayed on your screen. Current settings of speed, Xparity, duplex, and flow-@|control are honored. If you have issued a 'log Xsession' command, everything you see on your screen will also be recorded Xto your session log. This provides a way to "capture" files from systems Xthat don't have Kermit programs available. X XTo get back to your own system, you must type the escape character, which is XControl-@|Backslash (@q[^\]) unless you have changed it with the 'set escape' Xcommand, followed by a single-@|character command, such as 'c' for "close Xconnection". Single-@|character commands include: X@begin(description,leftmargin +8,indent -6,spread 0.4) Xc@\Close the connection X Xb@\Send a BREAK signal X X0@\(zero) send a null X Xs@\Give a status report about the connection X X@q[^\]@\Send Control-Backslash itself (whatever you have defined the Xescape character to be, typed twice in a row sends one copy of it). X@end(description) XLowercase and control equivalents for these letters are also accepted. A Xspace typed after the escape character is ignored. Any other character will Xproduce a beep. X XThe connect command simply displays incoming characters on the screen. It is Xassumed any screen control sequences sent by the host will be handled by Xthe firmware in your terminal or PC. If terminal emulation is desired, Xthen the connect command can invoked from the Unix command line (@q(-c) or X@q(-n)), piped through a terminal emulation filter, e.g. X@example(kermit -l /dev/acu -b 1200 -c | tek) X'c' is an acceptable non-unique abbreviation for 'connect'. X X@heading(The 'dial' command:) X XSyntax: @q(dial )@i(telephone-number-string) X XThis command controls dialout modems. The telephone-@|number-@|string may Xcontain modem-@|dialer commands, such as comma for Hayes pause, or '@q(&)' Xfor Ventel dialtone wait and '@q(%)' for Ventel pause. X XBecause modem dialers have strict requirements to override the carrier-@|detect Xsignal most Unix implementations expect, the sequence for dialing is more rigid Xthan with the rest of kermit's features. X XExample one: X@begin(example) X@ux<kermit -l /dev/cul0 -b 1200> XC-Kermit>@ux<set modem-dialer hayes> @i(hint: abbreviate) set m h XC-Kermit>@ux<dial 9,5551212> XConnected! XC-Kermit>@u<connect> @i(hint: abbreviate) c X@i(logon, request remote server, etc.) XC-Kermit> ... XC-Kermit>@u<quit> @i(hint: abbreviate) q X@end(example) Xthis disconnects modem, and unlocks line. X XExample two: X@begin(example) X@u(kermit) XC-Kermit>@ux(set modem-dialer ventel) XC-Kermit>@ux(set line /dev/cul0) XC-Kermit>@ux(dial 9&5551212%) XConnected! XC-Kermit> ... X@end(example) XExample three: X@begin(example) Xkermit XC-Kermit>@ux(take my-dial-procedure) XConnected! X X@i(file my-dial-procedure): Xset modem hayes Xset line /dev/tty99 Xdial 5551212 Xconnect X@end(example) XFor Hayes dialers, two important switch settings are #1 and #6. #1 Xshould be up so that the DTR is only asserted when the line is 'open'. X#6 should be up so carrier-@|detect functions properly. Switches #2 X(English versus digit result codes) and #4 (Hayes echoes modem commands) Xmay be in either position. X X@heading(The 'script' Command:) X XSyntax: @q(script )@i(expect send [expect send] . . .) X X"expect" has the syntax: @i(expect[-send-expect[-send-expect[...]]]) X XThis command facilitates logging into a remote system and/or invoking Xprograms or other facilities after login on a remote system. X XThis login script facility operates in a manner similar to that commonly Xused by the Unix uucp System's "@q(L.sys)" file entries. A login script Xis a sequence of the form: X@example(@i<expect send [expect send] . . .>) Xwhere @i(expect) is a prompt or message to be issued by the remote site, and X@i(send) is the string (names, numbers, etc) to return. The send may also be Xthe keyword EOT, to send Control-D, or BREAK, to send a break signal. Letters Xin send may be prefixed by '@q[~]' to send special characters. These are: X@begin(description,leftmargin +8,indent -4,spread 0) X@q(~b)@\backspace X X@q(~s)@\space X X@q(~q)@\'@q[?]'(trapped by Kermit's command interpreter) X X@q(~n)@\linefeed X X@q(~r)@\carriage return X X@q(~t)@\tab X X@q(~')@\single quote X X@q(~~)@\tilde X X@q(~")@\double quote X X@q(~c)@\don't append a carriage return X X@q(~)@i(o[o[o]])@\an octal character X@end(description) XAs with some uucp systems, sent strings are followed by @q(~r) unless they have Xa @q(~c). X XOnly the last 7 characters in each expect are matched. A null @i(expect), Xe.g. @q(~0) or two adjacent dashes, causes a short delay before proceeding Xto the next send sequence. A null expect always succeeds. X XAs with uucp, if the expect string does not arrive, the script attempt Xfails. If you expect that a sequence might not arrive, as with uucp, Xconditional sequences may be expressed in the form: X@example(@i<-send-expect[-send-expect[...]]>) Xwhere dashed sequences are followed as long as previous expects fail. X X@i(Expect/send) transactions can be easily be debugged by logging Xtransactions. This records all exchanges, both expected and actual. X XNote that '@q[\]' characters in login scripts, as in any other C-Kermit Xinteractive commands, must be doubled up. X XExample one: X XUsing a modem, dial a unix host site. Expect "login" (...gin), and if it Xdoesn't come, simply send a null string with a @q(~r). (Some Unixes Xrequire either an EOT or a BREAK instead of the null sequence, depending Xon the particular site's "logger" program.) After providing user id Xand password, respond "x" to a question-mark prompt, expect the Bourne Xshell "@q($)" prompt (and send return if it doesn't arrive). Then cd to Xdirectory kermit, and run the program called "wermit", entering the Xinteractive connect state after wermit is loaded. X@begin(example) Xset modem-dialer ventel Xset line /dev/tty77 Xset baud 1200 Xdial 9&5551212 Xscript gin:--gin:--gin: smith ssword: mysecret ~q x $--$ X cd~skermit $ wermit Xconnect X@end(example) X XExample two: X X@index(TELENET) XUsing a modem, dial the Telenet network. This network expects three Xreturns with slight delays between them. These are sent following Xnull expects. The single return is here sent as a null string, with Xa return appended by default. Four returns are sent to be safe before Xlooking for the prompt. Then the telenet id and password are entered. XThen telenet is instructed to connect to a host site (c 12345). The Xhost has a data switch, and to "which system" it responds "myhost". XThis is followed by a TOPS-20 logon, and a request to load Kermit, Xset even parity, and enter the server mode. Files Xare then exchanged. The commands are in a take file. The Xlogin command is split onto two lines for readability, though it Xis a single long line in the take file. X@begin(example) Xset modem-dialer hayes Xset line /dev/cul0 Xset baud 1200 Xdial 9,5551212 Xset parity even Xscript ~0 ~0 ~0 ~0 ~0 ~0 ~0 ~0 @@--@@--@@ id~saa001122 = 002211 @@ X c~s12345 ystem-c~s12345-ystem myhost @@ joe~ssecret @@ kermit X > set~sparity~seven > server Xsend some.stuff Xget some.otherstuff Xbye Xquit X@end(example) XSince these commands may be executed totally in the background, they Xcan also be scheduled. A typical shell script, which might be scheduled Xby cron, would be as follows (csh used for this example): X X@begin(example) X# X#keep trying to dial and log onto remote host and exchange files X#wait 10 minutes before retrying if dial or script fail. X# Xwhile ( 1 ) X kermit < tonight.cmd & X if ( ! $status ) break X sleep 600 Xend X@end(example) XFile tonight.cmd might have two takes in it, for example, one to take Xa file with the set modem, set line, set baud, dial, and script, and Xa second take of a file with send/get commands for the remote server. XThe last lines of @q(tonight.cmd) should be a bye and a quit. X X@heading(The 'help' Command:) X X@begin(example,leftmargin 0) X@r(Syntax:) help X@ @ @ @i(or): help @i(keyword) X@ @ @ @i(or): help {set, remote} @i(keyword) X@end(example) X XBrief help messages or menus are always available at interactive command Xlevel by typing a question mark at any point. A slightly more verbose form Xof help is available through the 'help' command. The 'help' command with Xno arguments prints a brief summary of how to enter commands and how to Xget further help. 'help' may be followed by one of the top-level C-Kermit Xcommand keywords, such as 'send', to request information about a command. XCommands such as 'set' and 'remote' have a further level of help. Thus you Xmay type 'help', 'help set', or 'help set parity'; each will provide a Xsuccessively more detailed level of help. X X X@heading(The 'exit' and 'quit' Commands:) X XThese two commands are identical. Both of them do the following: X X@begin(itemize,spread 0) XAttempt to insure that the terminal is returned to normal. X XRelinquish access to any communication line assigned via 'set line'. X XClose any open log files. X XRelinquish any uucp and multiuser locks on the communications line. X XHang up the modem, if the communications line supports data terminal ready. X@end(itemize) XAfter exit from C-Kermit, your default directory will be the same as when Xyou started the program. The 'exit' command is issued implicitly whenever XC-Kermit halts normally, e.g. after a command line invocation, or after certain Xkinds of interruptions. X X@section(C-Kermit under Berkeley or System III/V Unix:) X XC-Kermit may be interrupted at command level or during file transfer by Xtyping Control-C. The program will perform its normal exit function, Xrestoring the terminal. If a protocol transaction was in progress, an Xerror packet will be sent to the opposite Kermit so that it can terminate Xcleanly. X XC-Kermit may be invoked in the background ("&" on shell commmand line). XIf a background process is "killed", the user will have to manually Xremove any lock file and may need to restore the modem. This is because Xthe kill signal (@q<kill(@i[x],9)>) cannot be trapped by Kermit. X XDuring execution of a system command, C-Kermit can often be returned to Xcommand level by typing a single Control-C. (With System III/V, the Xusual interrupt function (often the DEL key) is replaced by Control-C.) XOn detecting Control-C, C-Kermit takes its normal exit, removing Xlock files and restoring the communication line, modem, and/or console Xterminal. X X@begin(description,leftmargin +4, indent -4) XUnder Berkeley Unix only:@\ XC-Kermit may also be interrupted by ^Z to put the process in the background. XIn this case the terminal is not restored. You will have to type XControl-J followed by "reset" followed by another Control-J to get your Xterminal back to normal. C-Kermit can be halted in a similar manner by Xtyping Control-@\Backslash, except that instead of moving it to the Xbackground, a core dump is produced. X XUnder System III/V Unix:@\ XThe Control-@q(\) character (or whatever control character has been Xselected via "set escape") at the C-Kermit command level Xis ignored; it is trapped and will not core-@|dump or interrupt Kermit. X@end(description) X XControl-C, Control-Z, and Control-@q(\) lose their normal functions during Xterminal connection and also during file transfer when the controlling tty Xline is being used for packet i/o. X XThe BSD implementation of C-Kermit has code to take advantage of a special Xnonstandard kernel-mode line driver, which boosts the speed of packet i/o Xsignificantly. The problem is that "raw" mode, needed for packet i/o, also Ximplies "cbreak" (character wakeup) mode, which is very expensive. The new Xline driver is a modification of the "berknet" driver, which allowed raw mode Xi/o to take place with process wakeup only upon receipt of a linefeed. The XBerknet driver, unfortunately, strips off the high order bit of each Xcharacter and does not allow the line terminator to be specified. The Xmodification allows all 8 bits to pass through unmolested, allows the wakeup Xcharacter to be specified, and allows the buffer to be tested or cleared. X XThe System III/V implementation uses regular kernel drivers, but "gulps" Xrawmode input in large blocks, thus overcomming the usual system call Xoverheads. X XIf you are running C-Kermit in "quiet mode" in the foreground, then Xinterrupting the program with a console interrupt like Control-C will not Xrestore the terminal to normal conversational operation. This is because Xthe system call to enable console interrupt traps will cause the program to Xblock if it's running in the background, and the primary reason for quiet Xmode is to allow the program to run in the background without blocking, so Xthat you can do other work in the foreground. X XIf C-Kermit is run in the background ("&" on shell commmand line), then Xthe interrupt signal (Control-C) (and System III/V quit signal) are Xignored. This prevents an interrupt signal intended for a foreground Xjob (say a compilation) from being trapped by a background Kermit session. X X X@section(C-Kermit on the DEC Pro-3xx with Venix 1@q(.)0) X XThe DEC Professional 300 series are PDP-11/23 based personal computers. XVenix 1@q(.)0 is a Unix v7 derivative. It should not be confused with XVenix 2@q(.)0, which resembles ATT System V. XC-Kermit runs in local mode on the Pro-3@i(xx) when invoked from the Xconsole; the default device is @q(/dev/com1). When connected to a Xremote system (using C-Kermit's 'connect' command), Pro/Venix itself (not XKermit) provides VT52 terminal emulation. X XDuring file transfer, the interruption and status commands (Control-A, XControl-F, etc) are not available. X X@section(C-Kermit Restrictions and Known Bugs) X X@begin(enumerate) X@ux(File renaming): When filename collision avoidance ("warning") is Xselected, C-Kermit constructs unique names by appending a generation number Xto the end of the file name. Currently, no checking is done to ensure that Xthe result is still within the maximum length for a file name. X X@ux(UUCP line locking): C-Kermit locks lines, to prevent UUCP and Xmultiuser conflicts, when it first opens a communications line. This Xoccurs either when 'set line' is issued, or if the '-l' argument is Xused, when the first 'dial', X'connect', or protocol operation occurs. The lock is released if Xanother 'set line' is issued, or if the program quits, exits, or is Xterminated by Control-C. XIf a user connects and returns to the shell command level, for example Xto initiate kermit by piped commands, on a communications line, the Xline lock is released when returning to the shell. XLocking is not needed, or used, if communications occur over the Xlocal terminal line (e.g. @q[/dev/tty]). In that case, there is no Xdifficultly with "piped" operations releasing locks and lines. X X@begin(multiple) X@ux(Removing stale lock files): XFor various reasons, lock files sometimes get left about after Xuucp or C-Kermit activities. (The most common reason is that Xthe uucp or C-Kermit activity was "killed" by a shell command.) XIf the lock file is owned by yourself, clearly you may remove Xit (presuming you are not running C-Kermit or uucp in the background Xwhen you discovered it). X XUucp supports a function, called uuclean, which is customarily Xused to remove these files after a predetermined age. If in doubt Xabout a lock file on the dial-out line you need, contact your Xsystem's operator. X@end(multiple) X X@ux(Modem controls): XIf connection is made over a communication line (rather than on Xthe controlling terminal line), and that line has modem controls, X(e.g. data terminal ready and carrier detection implementation), Xreturning to the shell level will disconnect the conversation. XIn that case, one should use interactive mode commands, and Xavoid use of piped shell-@|level operation (also see 'set modem-dialer' Xand 'dial' commands.) X X@ux(Login Scripts): The present login scripts implementation follows Xthe Unix conventions of uucp's "@q(L.sys)" file, rather than the normal XKermit "INPUT/@|OUTPUT" style. Volunteers have indicated an intent to Ximplement the Kermit standard for login scripts, and indeed even others Xmay be implemented in the future as needed. X X@begin(multiple) X@ux(Dial-out vs dial-in communications lines) XC-Kermit requires a dial-out line for the "set line" or "-l" options. XMost systems have some lines dedicated to dial-in, which they enable X"loggers" on, and some lines available for dial-out. Where a line Xmust be shared between dial-in and dial-out, several options are Xavailable (though they are, strictly speaking, outside the pervue of XC-Kermit). X XA simple shell program can be used to change directionality of the line Xif your Unix has the enable(8) and disable(8) commands. In that Xcase, the shell program could "grep" a "who" to see if anybody is Xlogged onto the desired line; if not, it could "disable" the line. XThe shell program will need to be set-uID'ed to root. The shell Xprogram can be called from kermit prior to a dial command, e.g., X"! mydisable.shellprog". Prior to the final "quit" from C-Kermit, Xanother shell program could be executed to "enable" the line Xagain. This program also needs to be set-uID'ed to root. X XIf your Unix lacks the enable(8) and disable(8) commands, another Xcommon technique works if your system supports the /etc/ttys file. XA shell program could call up an awk program to find the line Xin the file and set the enable byte to 0 (to directly disable the Xline). Likewise, it can be reenabled by a counterpart at the end. XIt may be necessary to pause for 60 seconds after modifying that Xfile before the logger sees it and actually disables the line. X@end(multiple) X X@begin(multiple) X@ux(Using C-Kermit on Local Area Networks): XC-Kermit can successfully operate at speeds up to 9600 baud over XLANs. Testing has, however, shown that most processors, whether XPC/XTs with PC/IX, or Vaxes, need flow control at these rates. XA command, "set flow x" should be issued to each end of this form Xof connection. X XIf the LAN is the sort with an interface card (or box, like the XSytek), then the interface card/box must be programmed to handle Xthe flow control characters (xon and xoff) at the card/box level X(rather than forwarding these characters to the remote site). This Xis because packetizing LANs will not deliver the xoff character Xto the other end, after packetization, until long after the receive Xbuffer has been overrun. X@end(multiple) X X@ux(Resetting terminal after abnormal termination or kill): When C-Kermit Xterminates abnormally (say, for example, by a kill Xcommand issued by the operator) the user may need to reset the terminal state. XIf commands do not seem to be accepted at the shell prompt, try XControl-J "stty sane" Control-J (use "reset" on Berkeley Unix). XThat should take the terminal out of "raw mode" if it was stuck there. X X@ux(Remote host commands may time-out on lengthy activity): XUsing "remote host" to instruct the C-Kermit server to invoke Unix Xfunctions (like "make") that might take a long time to produce output can cause Xtimeout conditions. X X X@ux(PC/IX Login Scripts -- Unfound Bug): XThough login scripts appear to work properly on most processors, in the Xcase of the PC/XT with PC/IX, it appears that longer scripts Xneed to be broken up into shorter scripts (invoked sequentially from Xthe take file). This is because the portion of the script handler Xwhich checks if an operation timed out seems to leave the processor Xin a strange state (i.e. hung). X@end(enumerate) X X@section(How to Build C-Kermit for a Unix System) X XThe C-Kermit files, as distributed from Columbia, all begin with the Xprefix "ck". You should make a directory for these files and then cd Xto it. A makefile is provided to build C-Kermit for various Unix systems. XAs distributed, the makefile has the name "@q(ckermi.mak)". You should Xrename it to "@q(makefile)" and then type "make xxx", where xxx is the Xsymbol for your system, for instance "make bsd" to make C-Kermit for X4.2 BSD Unix. The result will be a program called "wermit". You should Xtest this to make sure it works; if it does, then you can rename it to X"kermit" and install it for general use. See the makefile for a list of Xthe systems supported and the corresponding "make" arguments. X X@section(Adapting C-Kermit to Other Systems) X XC-Kermit is designed for portability. The level of portability is indicated Xin parentheses after the module name: "C" means any system that has a C Xcompiler that conforms to the description in "The C Programming Language" by XKernighan & Ritchie (Prentice-Hall, 1978). "Cf" is like "C", but also Xrequires "standard" features like printf and fprintf, argument passing via Xargv/argc, and so on, as described in Kernighan & Ritchie. "Unix" means the Xmodule should be useful under any Unix implementation; it requires features Xsuch as fork() and pipes. Anything else means that the module is particular Xto the indicated system. The modules are: X X@begin(description,leftmargin +4, indent -4) X@q<ckmain.c, ckermi.h, ckdebu.h (Cf)>:@\This is the main program. It contains Xdeclarations for global variables and Xa small amount of code to initialize some variables and invoke the command Xparser. In its distributed form, it assumes that command line arguments are Xpassed to it via argc and argv. Since this portion of code is only several Xlines long, it should be easy to replace for systems that have different Xstyles of user interaction. The header files define symbols and macros used Xby the various modules of C-Kermit. @q(ckdebu.h) is the only header file Xthat is included by all the C-Kermit modules, so it contains not only the Xdebug format definitions, but also any system-@|dependent typedefs. X X@q<wart.c (Cf), ckprot.w (C)>:@\The ckprot module embodies the Kermit protocol Xstate table and the code to accomplish state switching. It is written in X"wart", a language which may be regarded as a subset of the Unix "lex" lexical Xanalyzer generator. Wart implements enough of lex to allow the ckprot module Xto function. Lex itself was not used because it is proprietary (but lex may be Xused in place of wart with minor reformatting of @q(ckprot.w) -- removal of X@q(#includes) and comments, which must be reinserted into lex's output C Xprogram). The protocol module @q(ckprot.w) is read by wart, and a Xsystem-independent C program is produced. The syntax of a Wart program is Xillustrated by @q(ckprot.w), and is described in @q(ckwart.doc). X X@q<ckfns.c (C)>:@\The module contains all the Kermit protocol support functions X-- packet formation, encoding, decoding, block check calculation, filename and Xdata conversion, protocol parameter negotiation, and high-level interaction Xwith the communication line and file system. XTo accommodate small systems, this module has been split into two -- X@q(ckfns.c) and @q(ckfns2.c). X X@q(ckx???.c) (specific to system ???):@\For instance, @q(ckxunx.c) X(Berkeley, Venix, ATT System III/V, and other Unix systems) -- The ckx Xmodule contains the system-@|dependent primitives for communication line Xi/o, timers, and interrupts. Certain important variables are defined in Xthis module, which determine whether C-Kermit is by default remote or Xlocal, what the default communication device is, and so forth. The ckx Xmodule maintains its own private database of file descriptors and modes Xfor the console terminal and the file transfer communication line so Xthat other modules (like ckfns or the terminal connect module) need not Xbe concerned with them. This module will vary significantly among Unix Ximplementations since the sgtty/@|ioctl/@|termio functions and their Xarguments are among the least compatible areas of Unix. The @q(ckxunx.c) Xfile has conditional compilation for the variations of Unix. X X@q(ckz???.c) (specific to system ???):@\For instance, @q(ckzunx.c) (Berkeley, XVenix, System III/V Unix) -- The ckz module contains system-dependent Xprimitives for file i/o, wildcard (meta character) expansion, file existence Xand access checking, and system command execution. It maintains an internal Xdatabase of i/o "channels" (file pointers in the case of Unix) for the files XC-Kermit cares about -- the input file (the file which is being sent), the Xoutput file (the file being received), the various logs, the screen, and so Xforth. This module will vary little among Unix implementations except for the Xwildcard expansion code, which requires detailed knowledge of the directory Xstructure. The ckz module also defines variables containing the system command Xstrings used to perform certain functions like directory listing, file Xdeletion, etc. The @q(ckzunx.c) file has conditional compilation for the Xvariations of Unix. X X@begin(multiple) X@q(ckuser.h, ckuser.c, ckusr2.c, ckusr3.c) (Unix):@\This is the "user Xinterface" for C-Kermit. It includes the command parser, Xthe screen output functions, and console input functions. The command Xparser comes in two pieces -- the traditional Unix command line decoder X(which is quite small and compact), and the interactive keyword parser X(which is rather large). This module is fully replacable; its interface to Xthe other modules is very simple, and is explained at the beginning of the Xsource file. The ckuser module also includes code to execute any commands Xdirectly which don't require the Kermit protocol -- local file management, Xetc. The module is rated "Unix" because it makes occasional use of the Xsystem() function. X XNote that while ckuser is logically one module, it has been split up into Xthree C source files, plus a header file for the symbols they share in common. XThis is to accommodate small systems that cannot handle big modules. X@q(ckuser.c) has the command line and top-level interactive command parser; X@q(ckusr2.c) has the help command and strings; @q(ckusr3) has the set Xand remote commands along with the logging, screen, and "interrupt" functions. X@end(multiple) X X@q(ckcmd.c, ckcmd.h) (Cf):@\This is an interactive command parsing package Xdeveloped for C-Kermit. XIt is written portably enough to be usable on any system that has a C Xcompiler that supports functions like printf. The file name parsing Xfunctions depend upon primitives defined in the ckz module; if these Xprimitives cannot be supplied for a certain system, then the filename Xparsing functions can be deleted, and the package will still be useful Xfor parsing keywords, numbers, arbitrary text strings, and so forth. XThe style of interaction is the same as that found on the DECSYSTEM-20. X X@q(ckconu.c) (Unix):@\This is the connect module. As supplied, it should Xoperate in any Unix environment, or any C-based environment that provides the Xfork() function. The module requires access to global variables that specify Xline speed, parity, duplex, flow control, etc, but invokes functions from the Xckx module to accomplish the desired settings and input/output, and functions Xfrom the ckz module to perform session logging. There is no code for Xcontrolling modem signals. No terminal emulation is performed, but since Xstandard i/o is used for the console, this may be piped through a terminal Xemulation filter. The ckconu function may be entirely replaced, so long as Xthe global settings are honored by its replacement. PC implementations of XC-Kermit may require the ckcon module to do screen control, escape sequence Xinterpretation, etc, and may also wish to write special code to get the best Xpossible performance. X X@q(ckdial.c) (Unix):@\This is the dialer module. As supplied, it handles hayes Xand ventel modems. X X@q(cklogi.c) (Unix):@\This is the login script module. As supplied, it handles Xuucp-@|style logins. X@end(description) X XMoving C-Kermit to a new system entails: X@begin(enumerate) XCreating a new ckx module in C, assembler, or whatever language is Xmost appropriate for system programming on the new system. X XCreating a new ckz module, as above. X XIf the system is not Unix-like, then a new ckuser module may be required, Xas well as a different invocation of it from ckmain. X XIf the distributed connect module doesn't work or performs poorly, then Xit may be replaced. For instance, interrupt-driven i/o may be required, Xespecially if the system doesn't have forks. X@end(enumerate) XThose who favor a different style of user/program interaction from that Xprovided in @q(ckuser.c) may replace the entire module, for instance with one Xthat provides a mouse/@|window/@|icon environment, a menu/@|function-@|key Xenvironment, etc. X XA few guidelines should be followed to maintain portability: X@begin(itemize) XKeep variable and function names to 6 characters or less. X XKeep modules small. For instance, on a PDP-11 it is necessary to keep Xthe code segment of each module below 8K in order to allow the segment Xmapping to occur which is necessary to run programs larger than 64K on a Xnon-I-&-D-space machine. X XKeep strings short; many compilers have restrictive maximum lengths. X XKeep (f,s)printf arguments short. If these exceed some compiler dependent Xmaximum (perhaps as short as 128, after expansion) memory will be overwritten Xand the program will probably core dump. X XDo not introduce system dependencies into @q(ckprot.w) or @q(ckfns*.c). X@End(Itemize) XIn general, remember that this program will have to be compilable by old Xcompilers and runnable on small systems. X X !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckermi.doc part 1 sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.doc X X X X1. UNIX KERMIT X XProgram: Frank da Cruz, Bill Catchings, Jeff Damens, Columbia University; X Herm Fischer, Litton Data Systems, Van Nuys CA; contributions by X many others. XLanguage: C XDocumentation: X Frank da Cruz, Columbia University; Herm Fischer, Litton Data Sys- X tems, Van Nuys CA. XVersion: 4.2 XDate: March 1985 X X D R A F T X X NOTE -- This source for this documentation is written as input for the X Scribe text formatter. It needs to become input for two text format- X ters - Scribe and Nroff, the former for inclusion in the Kermit User X Guide, and the latter for Unix man pages. This might be done by defin- X ing formatting macros in M4, which generate the appropriate Scribe and X Nroff commands for sectioning, itemization, description, etc. X (Volunteers?) X XC-Kermit is a completely new implementation of Kermit, written modularly and Xtransportably in C. The protocol state transition table is written in wart, a X(not proprietary) lex-like preprocessor for C. System-dependent primitive func- Xtions are isolated into separately compiled modules so that the program should Xbe easily portable among Unix systems and also to non-Unix systems that have C Xcompilers. X X XUnix Kermit Capabilities At A Glance: X X Local operation: Yes X Local operation: Yes X Remote operation: Yes X Login scripts: Yes X Transfer text files: Yes X Transfer binary files: Yes X Wildcard send: Yes X File transfer interruption: Yes X Filename collision avoidance: Yes X Can time out: Yes X 8th-bit prefixing: Yes X Repeat count prefixing: Yes X Alternate block checks: Yes X Terminal emulation: Yes X Communication settings: Yes X Transmit BREAK: Yes X Support for dialout modems: Yes X IBM mainframe communication: Yes X Transaction logging: Yes X Session logging: Yes X Debug logging: Yes X Packet logging: Yes X Act as server: Yes X Talk to server: Yes X Advanced server functions: Yes X Local file management: Yes X Command/Init files: Yes X UUCP and multiuser line locking: Yes X File attributes: No X Command macros: No X Raw file transmit: No X XC-Kermit provides traditional Unix command line operation as well as inter- Xactive command prompting and execution. The command line options provide ac- Xcess to a minimal subset of C-Kermit's capabilities; the interactive command Xset is far richer. X XOn systems with dialout modems, C-Kermit can use command files and login Xscripts to essentially duplicate the file transfer functionality of uucp among Xheterogeneous operating systems, including by the use of scheduled (e.g. late Xnight) unattended operation. X X X1.1. The Unix File System X XConsult your Unix manual for details about the file system under your version Xof Unix. For the purposes of Kermit, several things are worth briefly noting. XUnix files generally have lowercase names. Unix directories are tree-struc- Xtured. Directory levels are separated by "/" characters. For example, X X /usr/foo/bar X Xdenotes the file bar in the directory /usr/foo. Wildcard or "meta" characters Xallow groups of files to be specified. "*" matches any string; "?" matches any Xsingle character. X XWhen C-Kermit is invoked with files specified on the Unix command line, the XUnix shell (Bourne Shell, C-Shell, etc) expands meta characters, and in this Xcase, a wider variety is available. For example, X X kermit -s ~/ck[x-z]*.[ch] X Xis expanded by the Berkeley C-Shell into a list of all the files in the user's Xhome directory (~/) that start with the characters "ck", followed by a single Xcharacter x, y, or z, followed by zero or more characters, followed by a dot, Xfollowed by one of the characters c or h. Internally, the C-Kermit program it- Xself expands only the "*" and "?" meta characters. X XUnix files are linear streams of 8-bit bytes. Text files consist of 7-bit AS- XCII characters, with the high bit off (0), and lines separated by the Unix Xnewline character, which is linefeed (LF, ASCII 10). This distinguishes Unix Xtext files from those on most other ASCII systems, in which lines are separated Xby a carriage-return linefeed sequence (CRLF, ASCII 13 followed by ASCII 10). XBinary files are likely to contain data in the high bits of the file bytes, and Xare not treated in terms of lines. X XWhen transferring files, C-Kermit will convert between upper and lower case Xfilenames and between LF and CRLF line terminators automatically, unless told Xto do otherwise. When binary files must be transferred, the program must be Xinstructed not to perform LF/CRLF conversion (-i on the command line or "set Xfile type" interactively; see below). X X X1.2. Command Line Operation X XThe C-Kermit command line syntax has been changed from that of earlier releases Xof Unix Kermit to conform to the "Proposed Syntax Standards for Unix System XCommands" put forth by Kathy Hemenway and Helene Armitage of AT&T Bell XLaboratories in Unix/World, Vol.1, No.3, 1984. The rules that apply are: X X - Command names must be between 2 and 9 characters ("kermit" is 6). X - Command names must include lower case letters and digits only. X - An option name is a single character. X - Options are delimited by '-'. X - Options with no arguments may be grouped (bundled) behind one X delimiter. X - Option-arguments cannot be optional. X - Arguments immediately follow options, separated by whitespace. X - The order of options does not matter. X - '-' preceded and followed by whitespace means standard input. X XA group of bundled options may end with an option that has an argument. X XThe following notation is used in command descriptions: X Xfn A Unix file specification, possibly containing the "wildcard" charac- X ters '*' or '?' ('*' matches all character strings, '?' matches any X single character). X Xfn1 A Unix file specification which may not contain '*' or '?'. X Xrfn A remote file specification in the remote system's own syntax, which X may denote a single file or a group of files. X Xrfn1 A remote file specification which should denote only a single file. X Xn A decimal number between 0 and 94. X Xc A decimal number between 0 and 127 representing the value of an ASCII X character. X Xcc A decimal number between 0 and 31, or else exactly 127, representing X the value of an ASCII control character. X X[ ] Any field in square braces is optional. X X{x,y,z} Alternatives are listed in curly braces. X XC-Kermit command line options may specify either actions or settings. If XC-Kermit is invoked with a command line that specifies no actions, then it will Xissue a prompt and begin interactive dialog. Action options specify either Xprotocol transactions or terminal connection. X X-s fn Send the specified file or files. If fn contains wildcard (meta) X characters, the Unix shell expands it into a list. If fn is '-' then X kermit sends from standard input, which must come from a file: X X kermit -s - < foo.bar X X or a parallel process: X X ls -l | kermit -s - X X You cannot use this mechanism to send terminal typein. If you want to X send a file whose name is "-" you can precede it with a path name, as X in X X kermit -s ./- X X-r Receive a file or files. Wait passively for files to arrive. X X-k Receive (passively) a file or files, sending them to standard output. X This option can be used in several ways: X X kermit -k X Displays the incoming files on your screen; to be used only in X "local mode" (see below). X X kermit -k > fn1 X Sends the incoming file or files to the named file, fn1. If more X than one file arrives, all are concatenated together into the X single file fn1. X X kermit -k | command X Pipes the incoming data (single or multiple files) to the indicated X command, as in X X kermit -k | sort > sorted.stuff X X-a fn1 If you have specified a file transfer option, you may specify an alter- X nate name for a single file with the -a option. For example, X X kermit -s foo -a bar X X sends the file foo telling the receiver that its name is bar. If more X than one file arrives or is sent, only the first file is affected by X the -a option: X X kermit -ra baz X X stores the first incoming file under the name baz. X X-x Begin server operation. May be used in either local or remote mode. X XBefore proceeding, a few words about remote and local operation are necessary. XC-Kermit is "local" if it is running on PC or workstation that you are using Xdirectly, or if it is running on a multiuser system and transferring files over Xan external communication line -- not your job's controlling terminal or con- Xsole. C-Kermit is remote if it is running on a multiuser system and transfer- Xring files over its own controlling terminal's communication line, connected to Xyour PC or workstation. X XIf you are running C-Kermit on a PC, it is in local mode by default, with the X"back port" designated for file transfer and terminal connection. If you are Xrunning C-Kermit on a multiuser (timesharing) system, it is in remote mode un- Xless you explicitly point it at an external line for file transfer or terminal Xconnection. The following command sets C-Kermit's "mode": X X-l dev Line -- Specify a terminal line to use for file transfer and terminal X connection, as in X X kermit -l /dev/ttyi5 X XWhen an external line is being used, you might also need some additional op- Xtions for successful communication with the remote system: X X-b n Baud -- Specify the baud rate for the line given in the -l option, as X in X X kermit -l /dev/ttyi5 -b 9600 X X This option should always be included with the -l option, since the X speed of an external line is not necessarily what you expect. X X-p x Parity -- e,o,m,s,n (even, odd, mark, space, or none). If parity is X other than none, then the 8th-bit prefixing mechanism will be used for X transferring 8-bit binary data, provided the opposite Kermit agrees. X The default parity is none. X X-t Specifies half duplex, line turnaround with XON as the handshake X character. X XThe following commands may be used only with a C-Kermit which is local -- ei- Xther by default or else because the -l option has been specified. X X-g rfn Actively request a remote server to send the named file or files; rfn X is a file specification in the remote host's own syntax. If fn happens X to contain any special shell characters, like '*', these must be X quoted, as in X X kermit -g x\*.\? X X-f Send a 'finish' command to a remote server. X X-c Establish a terminal connection over the specified or default com- X munication line, before any protocol transaction takes place. Get back X to the local system by typing the escape character (normally X Control-Backslash) followed by the letter 'c'. X X-n Like -c, but after a protocol transaction takes place; -c and -n may X both be used in the same command. The use of -n and -c is illustrated X below. X XOn a timesharing system, the -l and -b options will also have to be included Xwith the -r, -k, or -s options if the other Kermit is on a remote system. X XIf C-Kermit is in local mode, the screen (stdout) is continously updated to Xshow the progress of the file transer. A dot is printed for every four data Xpackets, other packets are shown by type (e.g. 'S' for Send-Init), 'T' is Xprinted when there's a timeout, and '%' for each retransmission. In addition, Xyou may type (to stdin) certain "interrupt" commands during file transfer: X X Control-F: Interrupt the current File, and go on to the next (if any). X Control-B: Interrupt the entire Batch of files, terminate the transaction. X Control-R: Resend the current packet X Control-A: Display a status report for the current transaction. X XThese interrupt characters differ from the ones used in other Kermit implemen- Xtations to avoid conflict with Unix shell interrupt characters. With System XIII and System V implementations of Unix, interrupt commands must be preceeded Xby the escape character (e.g. control-\). X XSeveral other command-line options are provided: X X-i Specifies that files should be sent or received exactly "as is" with no X conversions. This option is necessary for transmitting binary files. X It may also be used to slightly boost efficiency in Unix-to-Unix trans- X fers of text files by eliminating CRLF/newline conversion. X X-w Write-Protect -- Avoid filename collisions for incoming files. X X-q Quiet -- Suppress screen update during file transfer, for instance to X allow a file transfer to proceed in the background. X X-d Debug -- Record debugging information in the file debug.log in the cur- X rent directory. Use this option if you believe the program is mis- X behaving, and show the resulting log to your local kermit maintainer. X X-h Help -- Display a brief synopsis of the command line options. X XThe command line may contain no more than one protocol action option. X XFiles are sent with their own names, except that lowercase letters are raised Xto upper, pathnames are stripped off, tilde ('~') characters changed to 'X', Xand if the file name begins with a period, an 'X' is inserted before it. In- Xcoming files are stored under their own names except that uppercase letters are Xlowered, and, if -w was specified, a "generation number" is appended to the Xname if it has the same name as an existing file which would otherwise be over- Xwritten. If the -a option is included, then the same rules apply to its ar- Xgument. The file transfer display shows any transformations performed upon Xfilenames. X XDuring transmission, files are encoded as follows: X X - Control characters are converted to prefixed printables. X X - Sequences of repeated characters are collapsed via repeat counts, if X the other Kermit is also capable of repeated-character compression. X X - If parity is being used on the communication line, data characters X with the 8th (parity) bit on are specially prefixed, provided the X other Kermit is capable of 8th-bit prefixing (if not, 8-bit binary X files cannot be successfully transferred). X X - Conversion is done between Unix newlines and carriage-return-linefeed X sequences unless the -i option was specified. X X XCommand Line Examples: X X kermit -l /dev/ttyi5 -b 1200 -cn -r X XThis command connects you to the system on the other end of ttyi5 at 1200 baud, Xwhere you presumably log in and run Kermit with a 'send' command. After you Xescape back, C-Kermit waits for a file (or files) to arrive. When the file Xtransfer is completed, you are again connected to the remote system so that you Xcan logout. X X kermit -l /dev/ttyi4 -b 1800 -cntp m -r -a foo X XThis command is like the preceding one, except the remote system in this case Xuses half duplex communication with mark parity. The first file that arrives Xis stored under the name foo. X X X kermit -l /dev/ttyi6 -b 9600 -c | tek X XThis example uses Kermit to connect your terminal to the system at the other Xend of ttyi6. The C-Kermit terminal connection does not provide any particular Xterminal emulation, so C-Kermit's standard i/o is piped through a X(hypothetical) program called tek, which performs (say) Tektronix emulation. X X X kermit -l /dev/ttyi6 -b 9600 -nf X XThis command would be used to shut down a remote server and then connect to the Xremote system, in order to log out or to make further use of it. The -n option Xis invoked after -f (-c would have been invoked before). X X X kermit -l /dev/ttyi6 -b 9600 -qg foo.\* & X XThis command causes C-Kermit to be invoked in the background, getting a group Xof files from a remote server (note the quoting of the '*' character). No dis- Xplay occurs on the screen, and the keyboard is not sampled for interruption Xcommands. This allows other work to be done while file transfers proceed in Xthe background. X X X kermit -l /dev/ttyi6 -b 9600 -g foo.\* > foo.log < /dev/null & X XThis command is like the previous one, except the file transfer display has Xbeen redirected to the file foo.log. Standard input is also redirected, to Xprevent C-Kermit from sampling it for interruption commands. X X X kermit -iwx X XThis command starts up C-Kermit as a server. Files are transmitted with no Xnewline/carriage-return-linefeed conversion; the -i option is necessary for bi- Xnary file transfer and useful for Unix-to-Unix transfers. Incoming files that Xhave the same names as existing files are given new, unique names. X X X kermit -l /dev/ttyi6 -b 9600 X XThis command sets the communication line and speed. Since no action is Xspecified, C-Kermit issues a prompt and enters an interactive dialog with you. XAny settings given on the command line remain in force during the dialog, un- Xless explicitly changed. X X X kermit X XThis command starts up Kermit interactively with all default settings. X XA final example shows how Unix Kermit might be used to send an entire directory Xtree from one Unix system to another, using the tar program as Kermit's stan- Xdard input and output. On the orginating system, in this case the remote, type X(for instance): X X X tar cf - /usr/fdc | kermit -is - X XThis causes tar to send the directory /usr/fdc (and all its files and all its Xsubdirectories and all their files...) to standard output instead of to a tape; Xkermit receives this as standard input and sends it as a binary file. On the Xreceiving system, in this case the local one, type (for instance): X X X kermit -il /dev/ttyi5 -b 9600 -k | tar xf - X XKermit receives the tar archive, and sends it via standard output to its own Xcopy of tar, which extracts from it a replica of the original directory tree. X X XExit Status Codes: X XKermit returns an exit status of zero, except when a fatal error is encoun- Xtered, where the exit status is set to one. With background operation (e.g., X'&' on invoking command line), driven by scripted interactive commands X(redirected standard input and/or take files), any failed interactive command X(such as failed dial or script attempt) causes the fatal error exit. X X X1.3. Interactive Operation X XC-Kermit's interactive command prompt is "C-Kermit>". In response to this Xprompt, you may type any valid command. C-Kermit executes the command and then Xprompts you for another command. The process continues until you instruct the Xprogram to terminate. X XCommands begin with a keyword, normally an English verb, such as "send". You Xmay omit trailing characters from any keyword, so long as you specify suf- Xficient characters to distinguish it from any other keyword valid in that Xfield. Certain commonly-used keywords (such as "send", "receive", "connect") Xhave special non-unique abbreviations ("s" for "send", "r" for "receive", "c" Xfor "connect"). X XCertain characters have special functions in interactive commands: X X ? Question mark, typed at any point in a command, will produce a message X explaining what is possible or expected at that point. Depending on X the context, the message may be a brief phrase, a menu of keywords, or X a list of files. X X ESC (The Escape or Altmode key) -- Request completion of the current X keyword or filename, or insertion of a default value. The result will X be a beep if the requested operation fails. X X DEL (The Delete or Rubout key) -- Delete the previous character from the X command. You may also use BS (Backspace, Control-H) for this function. X X ^W (Control-W) -- Erase the rightmost word from the command line. X X ^U (Control-U) -- Erase the entire command. X X ^R (Control-R) -- Redisplay the current command. X X SP (Space) -- Delimits fields (keywords, filenames, numbers) within a com- X mand. HT (Horizontal Tab) may also be used for this purpose. X X CR (Carriage Return) -- Enters the command for execution. LF (Linefeed) X or FF (formfeed) may also be used for this purpose. X X \ (Backslash) -- Enter any of the above characters into the command, X literally. To enter a backslash, type two backslashes in a row (\\). X XYou may type the editing characters (DEL, ^W, etc) repeatedly, to delete all Xthe way back to the prompt. No action will be performed until the command is Xentered by typing carriage return, linefeed, or formfeed. If you make any mis- Xtakes, you will receive an informative error message and a new prompt -- make Xliberal use of '?' and ESC to feel your way through the commands. One impor- Xtant command is "help" -- you should use it the first time you run C-Kermit. X XInteractive C-Kermit accepts commands from files as well as from the keyboard. XWhen you enter interactive mode, C-Kermit looks for the file .kermrc in your Xhome or current directory (first it looks in the home directory, then in the Xcurrent one) and executes any commands it finds there. These commands must be Xin interactive format, not Unix command-line format. A "take" command is also Xprovided for use at any time during an interactive session. Command files may Xbe nested to any reasonable depth. X XHere is a brief list of C-Kermit interactive commands: X ! Execute a Unix shell command. X bye Terminate and log out a remote Kermit server. X close Close a log file. X connect Establish a terminal connection to a remote system. X cwd Change Working Directory. X dial Dial a telephone number. X directory Display a directory listing. X echo Display arguments literally. X exit Exit from the program, closing any open logs. X finish Instruct a remote Kermit server to exit, but not log out. X get Get files from a remote Kermit server. X help Display a help message for a given command. X log Open a log file -- debugging, packet, session, transaction. X quit Same as 'exit'. X receive Passively wait for files to arrive. X remote Issue file management commands to a remote Kermit server. X script Execute a login script with a remote system. X send Send files. X server Begin server operation. X set Set various parameters. X show Display values of 'set' parameters. X space Display current disk space usage. X statistics Display statistics about most recent transaction. X take Execute commands from a file. X XThe 'set' parameters are: X block-check Level of packet error detection. X delay How long to wait before sending first packet. X duplex Specify which side echoes during 'connect'. X end-of-packet Terminator for outbound packets. X escape-character Character to prefix "escape commands" during 'connect'. X file Set various file parameters. X flow-control Communication line full-duplex flow control. X handshake Communication line half-duplex turnaround character. X line Communication line device name. X modem-dialer Type of modem-dialer on communication line. X packet-length Maximum length for packets. X pad-character Character to use for inter-packet padding. X padding How much inter-packet padding to use. X parity Communication line character parity. X prompt Change the C-Kermit program's prompt. X speed Communication line speed. X start-of-packet Control character to mark beginning of packets. X timeout Timer interval to detect lost packets. X XThe 'remote' commands are: X cwd Change remote working directory. X delete Delete remote files. X directory Display a listing of remote file names. X help Request help from a remote server. X host Issue a command to the remote host in its own command language X space Display current disk space usage on remote system. X type Display a remote file on your screen. X who Display who's logged in, or get information about a user. X XMost of these commands are described adequately in the Kermit User Guide. Spe- Xcial aspects of certain Unix Kermit commands are described below. X X X THE 'SEND' COMMAND X XSyntax: send fn - or - send fn1 rfn1 X XSend the file or files denoted by fn to the other Kermit, which should be run- Xning as a server, or which should be given the 'receive' command. Each file is Xsent under its own name (as described above, or as specified by the 'set file Xnames' command). If the second form is used, i.e. with fn1 denoting a single XUnix file, rfn1 may be specified as a name to send it under. The 'send' com- Xmand may be abbreviated to 's', even though 's' is not a unique abbreviation Xfor a top-level C-Kermit command. X XThe wildcard (meta) characters '*' and '?' are accepted in fn. If '?' is to be Xincluded, it must be prefixed by '\' to override its normal function of provid- Xing help. '*' matches any string, '?' matches any single character. Other Xnotations for file groups, like '[a-z]og', are not available in interactive Xcommands (though of course they are available on the command line). When fn Xcontains '*' or '?' characters, there is a limit to the number of files that Xcan be matched, which varies from system to system. If you get the message X"Too many files match" then you'll have to make a more judicious selection. If Xfn was of the form X X usr/longname/anotherlongname/* X Xthen C-Kermit's string space will fill up rapidly -- try doing a cwd (see Xbelow) to the path in question and reissuing the command. X XNote -- C-Kermit sends only from the current or specified directory. It does Xnot traverse directory trees. If the source directory contains subdirectories, Xthey will be skipped. Conversely, C-Kermit does not create directories when Xreceiving files. If you have a need to do this, you can pipe tar through XC-Kermit, as shown in the example on page 3, or under System III/V Unix you can Xuse cpio. X XAnother Note -- C-Kermit does not skip over "invisible" files that match the Xfile specification; Unix systems usually treat files whose names start with a Xdot (like .login, .cshrc, and .kermrc) as invisible. X X X THE 'RECEIVE' COMMAND X XSyntax: receive - or - receive fn1 X XPassively wait for files to arrive from the other Kermit, which must be given Xthe 'send' command -- the 'receive' command does not work in conjunction with a Xserver (use 'get' for that). If fn1 is specified, store the first incoming Xfile under that name. The 'receive' command may be abbreviated to 'r'. X X X THE 'GET' COMMAND: X XSyntax: get rfn X X or: get X rfn X fn1 X XRequest a remote Kermit server to send the named file or files. Since a remote Xfile specification (or list) might contain spaces, which normally delimit Xfields of a C-Kermit command, an alternate form of the command is provided to Xallow the inbound file to be given a new name: type 'get' alone on a line, and Xyou will be prompted separately for the remote and local file specifications, Xfor example X X C-Kermit>get X Remote file specification: foo X Local name to store it under: bar X XAs with 'receive', if more than one file arrives as a result of the 'get' com- Xmand, only the first will be stored under the alternate name given by fn1; the Xremaining files will be stored under their own names if possible. If a '?' is Xto be included in the remote file specification, you must prefix it with '\' to Xsuppress its normal function of providing help. X X X THE 'SERVER' COMMAND: X XThe 'server' command places C-Kermit in "server mode" on the currently selected Xcommunication line. All further commands must arrive as valid Kermit packets Xfrom the Kermit on the other end of the line. The Unix Kermit server can Xrespond to the following commands: X XCommand Server Response X get Sends files X send Receives files X bye Attempts to log itself out X finish Exits to level from which it was invoked X remote directory Sends directory lising X remote delete Removes files X remote cwd Changes working directory X remote type Sends files to your screen X remote space Reports about its disk usage X remote who Shows who's logged in X remote host Executes a Unix shell command X remote help Lists these capabilities X XNote that the Unix Kermit server cannot always respond to a BYE command. It Xwill attempt to do so using "kill(0,9)", but this will not work on all systems Xor under all conditions. For instance, the C-Shell changes your process group, Xso that the process id of 0 does not refer to what you might expect. X XIf the Kermit server is directed at an external line (i.e. it is in "local Xmode") then the console may be used for other work if you have 'set file dis- Xplay off'; normally the program expects the console to be used to observe file Xtransfers and enter status queries or interruption commands. The way to get XC-Kermit into background operation from interactive command level varies from Xsystem to system (e.g. on Berkeley Unix you would halt the program with ^Z and Xthen use the C-Shell 'bg' command to continue it in the background). The more Xcommon method is to invoke the program with the desired command line arguments, Xincluding "-q", and with a terminating "&". X XWhen the Unix Kermit server is given a 'remote host' command, it executes it Xusing the shell invoked upon login to the remote system, e.g. the Bourne shell Xor the Berkeley C-Shell. (Note -- this is in distinction to the local "!" Xshell escape, which always uses the Bourne shell; see below). X X X THE 'REMOTE', 'BYE', AND 'FINISH' COMMANDS: X XC-Kermit may itself request services from a remote Kermit server. In addition Xto the 'send' and 'get' commands, the following may also be used: X X remote cwd [directory] X If the optional remote directory specification is included, you will be X prompted on a separate line for a password, which will not echo as you X type it. X X remote delete rfn delete remote file or files. X remote directory [rfn] directory listing of remote files. X remote host command command in remote host's own command language. X remote space disk usage report from remote host. X remote type [rfn] display remote file or files on the screen. X remote who [user] display information about who's logged in. X remote help display remote server's capabilities. X X bye and finish: X When connected to a remote Kermit server, these commands cause the X remote server to terminate; 'finish' returns it to Kermit or system X command level (depending on the implementation or how the program was X invoked); 'bye' also requests it to log itself out. X X X THE 'LOG' AND 'CLOSE' COMMANDS: X XSyntax: log {debugging, packets, session, transactions} [ fn1 ] X XC-Kermit's progress may be logged in various ways. The 'log' command opens a Xlog, the 'close' command closes it. In addition, all open logs are closed by Xthe 'exit' and 'quit' commands. A name may be specified for a log file; if the Xname is omitted, the file is created with a default name as shown below. X Xlog debugging X This produces a voluminous log of the internal workings of C-Kermit, of use X to Kermit developers or maintainers in tracking down suspected bugs in the X C-Kermit program. Use of this feature dramatically slows down the Kermit X protocol. Default name: debug.log. X Xlog packets X This produces a record of all the packets that go in and out of the com- X munication port. This log is of use to Kermit maintainers who are tracking X down protocol problems in either C-Kermit or any Kermit that C-Kermit is X connected to. Default name: packet.log. X Xlog session X This log will contain a copy of everything you see on your screen during X the 'connect' command, except for local messages or interaction with local X escape commands. Default name: session.log. X Xlog transactions X The transaction log is a record of all the files that were sent or received X while transaction logging was in effect. It includes time stamps and X statistics, filename transformations, and records of any errors that may X have occurred. The transaction log allows you to have long unattended file X transfer sessions without fear of missing some vital screen message. X Default name: transaction.log. X XThe 'close' command explicitly closes a log, e.g. 'close debug'. X X X LOCAL FILE MANAGEMENT COMMANDS: X XUnix Kermit allows some degree of local file management from interactive com- Xmand level: X Xdirectory [fn] X Displays a listing of the names, modes, sizes, and dates of files matching X fn (which defaults to '*'). Equivalent to 'ls -l'. X Xcwd [directory-name] X Changes Kermit's working directory to the one given, or to the your default X directory if the directory name is omitted. Equivalent to 'cd'. X Xspace X Display information about disk space and/or quota in the current directory X and device. X X! command X The command is executed by the Unix shell. Use this for all other file X management commands. This command has certain peculiarities: X X - The Bourne shell is used. X - At least one space must separate the '!' from the shell command. X - A 'cd' command executed in this manner will have no effect -- use X the C-Kermit 'cwd' command instead. X X X THE 'SET' AND 'SHOW' COMMANDS: X XSince Kermit is designed to allow diverse systems to communicate, it is often Xnecessary to issue special instructions to allow the program to adapt to Xpeculiarities of the another system or the communication path. These instruc- Xtions are accomplished by the 'set' command. The 'show' command may be used to Xdisplay current settings. Here is a brief synopsis of settings available in Xthe current release of C-Kermit: X Xblock-check {1, 2, 3} X Determines the level of per-packet error detection. "1" is a single- X character 6-bit checksum, folded to include the values of all bits from X each character. "2" is a 2-character, 12-bit checksum. "3" is a X 3-character, 16-bit cyclic redundancy check (CRC). The higher the block X check, the better the error detection and correction and the higher the X resulting overhead. Type 1 is most commonly used; it is supported by all X Kermit implementations, and it has proven adequate in most circumstances. X Types 2 or 3 would be used to advantage when transferring 8-bit binary X files over noisy lines. X Xdelay n X How many seconds to wait before sending the first packet after a 'send' X command. Used in remote mode to give you time to escape back to your local X Kermit and issue a 'receive' command. Normally 5 seconds. X Xduplex {full, half} X For use during 'connect'. Specifies which side is doing the echoing; X 'full' means the other side, 'half' means C-Kermit must echo typein itself. X Xend-of-packet cc X Specifies the control character needed by the other Kermit to recognize the X end of a packet. C-Kermit sends this character at the end of each packet. X Normally 13 (carriage return), which most Kermit implementations require. X Other Kermits require no terminator at all, still others may require a dif- X ferent terminator, like linefeed (10). X !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckermi.doc part 2 sed '1,$s/^X//' <<\!FUNKY!STUFF! >> ckermi.doc Xescape-character cc X For use during 'connect' to get C-Kermit's attention. The escape character X acts as a prefix to an 'escape command', for instance to close the connec- X tion and return to C-Kermit or Unix command level. The normal escape X character is Control-Backslash (28). The escape character is also used in X System III/V implementations, to prefix interrupt commands during file X transfers. X Xfile {display, names, type, warning} X Establish various file-related parameters: X X display {on, off} X Normally 'on'; when in local mode, display progress of file transfers X on the screen (stdout), and listen to the keyboard (stdin) for inter- X ruptions. If off (-q on command line) none of this is done, and the X file transfer may proceed in the background oblivious to any other work X concurrently done at the console terminal. X X names {converted, literal} X Normally converted, which mean that outbound filenames have path X specifications stripped, lowercase letters raised to upper, tildes and X extra periods changed to X's, and an X inserted in front of any name X that starts with period. Incoming files have uppercase letters X lowered. Literal means that none of these conversions are done; there- X fore, any directory path appearing in a received file specification X must exist and be write-accessible. When literal naming is being used, X the sender should not use path names in the file specification unless X the same path exists on the target system and is writable. X X type {binary, text} X Normally text, which means that conversion is done between Unix newline X characters and the carriage-return/linefeed sequences required by the X canonical Kermit file transmission format, and in common use on non- X Unix systems. Binary means to transmit file contents without conver- X sion. Binary ('-i' in command line notation) is necessary for binary X files, and desirable in all Unix-to-Unix transactions to cut down on X overhead. X X warning {on, off} X Normally off, which means that incoming files will silently overwrite X existing files of the same name. When on ('-w' on command line) Kermit X will check if an arriving file would overwrite an existing file; if so, X it will construct a new name for the arriving file, of the form foo~n, X where foo is the name they share and n is a "generation number"; if foo X exists, then the new file will be called foo~1. If foo and foo~1 ex- X ist, the new file will be foo~2, and so on. X Xflow-control {none, xon/xoff} X Normally xon/xoff for full duplex flow control. Should be set to 'none' if X the other system cannot do xon/xoff flow control. X Xhandshake {xon, xoff, cr, lf, bell, esc, none} X Normally none. Otherwise, half-duplex communication line turnaround hand- X shaking is done, which means Unix Kermit will not reply to a packet until X it has received the indicated handshake character or has timed out waiting X for it. X Xline [device-name] X The device name for the communication line to be used for file transfer and X terminal connection, e.g. /dev/ttyi3. If you specify a device name, Kermit X will be in local mode, and you should remember to issue any other necessary X 'set' commands, such as 'set speed'. If you omit the device name, Kermit X will revert to its default mode of operation. X Xmodem-dialer {direct, hayes, ventel} X The type of modem dialer on the communication line. "Direct" indicates ei- X ther there is no dialout modem, or that if the line requires carrier detec- X tion to open, then 'set line' will hang waiting for an incoming call. X "Hayes" and "Ventel" indicate that the subsequent 'set line' (or the -l X argument) will prepare for a subsequent 'dial' command for Hayes and Ventel X dialers, respectively. X Xpacket-length n X Specify the maximum packet length to use. Normally 90. Shorter packet X lengths can be useful on noisy lines, or with systems or front ends or net- X works that have small buffers. The shorter the packet, the higher the X overhead, but the lower the chance of a packet being corrupted by noise, X and the less time to retransmit corrupted packets. X Xpad-character cc X C-Kermit normally does not need to have incoming packets preceded with pad X characters. This command allows C-Kermit to request the other Kermit to X use cc as a pad character. Default cc is NUL, ASCII 0. X Xpadding n X How many pad characters to ask for, normally 0. X Xparity {even, odd, mark, space, none} X Specify character parity for use in packets and terminal connection, nor- X mally none. If other than none, C-Kermit will seek to use the 8th-bit X prefixing mechanism for transferring 8-bit binary data, which can be used X successfully only if the other Kermit agrees; if not, 8-bit binary data X cannot be successfully transferred. X Xprompt [string] X The given string will be substituted for "C-Kermit>" as this program's X prompt. If the string is omitted, the prompt will revert to "C-Kermit>". X Xspeed {0, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 9600} X The baud rate for the external communication line. This command cannot be X used to change the speed of your own console terminal. Many Unix systems X are set up in such a way that you must give this command after a 'set line' X command before you can use the line. X Xstart-of-packet cc X The Kermit packet prefix is Control-A (1). The only reasons it should ever X be changed would be: Some piece of equipment somewhere between the two Ker- X mit programs will not pass through a Control-A; or, some piece of of equi- X pment similarly placed is echoing its input. In the latter case, the X recipient of such an echo can change the packet prefix for outbound packets X to be different from that of arriving packets, so that the echoed packets X will be ignored. The opposite Kermit must also be told to change the X prefix for its inbound packets. Unix Kermit presently can be told to X change only its outbound packet prefix. X Xtimeout n X Normally, each Kermit partner sets its packet timeout interval based on X what the opposite Kermit requests. This command allows you to override the X normal procedure and specify a timeout interval. If you specify 0, then no X timeouts will occur, and Unix Kermit will wait forever for expected packets X to arrive. X X X THE 'SHOW' COMMAND: X XSyntax: show {parameters, versions} X XThe show command displays the values of all the 'set' parameters described Xabove. If you type 'show versions', then C-Kermit will display the version Xnumbers and dates of all its internal modules. You should use the 'show Xversions' command to ascertain the vintage of your Kermit program before Xreporting problems to Kermit maintainers. X X X THE 'STATISTICS' COMMAND: X XThe statistics command displays information about the most recent Kermit Xprotocol transaction, including file and communication line i/o, as well as Xwhat encoding options were in effect (such as 8th-bit prefixing, repeat-count Xcompression). X X X THE 'TAKE' AND 'ECHO' COMMANDS: X XSyntax: take fn1 X XThe 'take' command instructs C-Kermit to execute commands from the named file. XThe file may contain any interactive C-Kermit commands, including 'take'; com- Xmand files may be nested to any reasonable depth. The 'echo' command may be Xused within command files to issue greetings, announce progress, etc. X XCommand files are in exactly the same syntax as interactive commands. Note Xthat this implies that if you want to include special characters like question Xmark or backslash that you would have to quote with backslash when typing in- Xteractive commands, you must quote these characters the same way in command Xfiles. X XCommand files may be used in lieu of command macros, which have not been imple- Xmented in this version of C-Kermit. For instance, if you commonly connect to a Xsystem called 'B' that is connected to ttyh7 at 4800 baud, you could create a Xfile called b containing the commands X X set line /dev/ttyh7 X set speed 4800 X echo Connecting to System B... X connect X Xand then simply type 'take b' (or 't b' since no other commands begin with the Xletter 't') whenever you wished to connect to system B. X XFor connecting to IBM mainframes, a number of 'set' commands are required; Xthese, too, are conveniently collected into a 'take' file like this one: X X set speed 1200 X set parity mark X set handshake xon X set flow-control none X set duplex half X XAn implicit 'take' command is executed upon your .kermrc file upon C-Kermit's Xinitial entry into interactive dialog. The .kermrc file should contain 'set' Xor other commands you want to be in effect at all times. For instance, you Xmight want override the default action when incoming files have the same names Xas existing files -- in that case, put the command X X set file warning on X Xin your .kermrc file. X XCommands executed from take files are not echoed at the terminal. If you want Xto see the commands as well as their output, you could feed the command file to XC-Kermit via redirected stdin, as in X X 'kermit < cmdfile' XErrors encountered during execution of take files (such as failure to complete Xdial or script operations) cause termination of the current take file, popping Xto the take file that invoked it, or to interactive level. When kermit is ex- Xecuted in the background, errors during execution of a take file are fatal. X X X THE 'CONNECT' COMMAND: X XThe connect command links your terminal to another computer as if it were a lo- Xcal terminal to that computer, through the device specified in the most recent X'set line' command, or through the default device if your system is a PC or Xworkstation. All characters you type at your keyboard are sent out the com- Xmunication line, all characters arriving at the communication port are dis- Xplayed on your screen. Current settings of speed, parity, duplex, and flow- Xcontrol are honored. If you have issued a 'log session' command, everything Xyou see on your screen will also be recorded to your session log. This Xprovides a way to "capture" files from systems that don't have Kermit programs Xavailable. X XTo get back to your own system, you must type the escape character, which is XControl-Backslash (^\) unless you have changed it with the 'set escape' com- Xmand, followed by a single-character command, such as 'c' for "close Xconnection". Single-character commands include: X X c Close the connection X b Send a BREAK signal X 0 (zero) send a null X s Give a status report about the connection X ^\ Send Control-Backslash itself (whatever you have defined the escape X character to be, typed twice in a row sends one copy of it). X XLowercase and control equivalents for these letters are also accepted. A space Xtyped after the escape character is ignored. Any other character will produce Xa beep. X XThe connect command simply displays incoming characters on the screen. It is Xassumed any screen control sequences sent by the host will be handled by the Xfirmware in your terminal or PC. If terminal emulation is desired, then the Xconnect command can invoked from the Unix command line (-c or -n), piped Xthrough a terminal emulation filter, e.g. X X kermit -l /dev/acu -b 1200 -c | tek X X'c' is an acceptable non-unique abbreviation for 'connect'. X X X THE 'DIAL' COMMAND: X XSyntax: dial telephone-number-string X XThis command controls dialout modems. The telephone-number-string may contain Xmodem-dialer commands, such as comma for Hayes pause, or '&' for Ventel dial- Xtone wait and '%' for Ventel pause. X XBecause modem dialers have strict requirements to override the carrier-detect Xsignal most Unix implementations expect, the sequence for dialing is more rigid Xthan with the rest of kermit's features. X XExample one: X X kermit -l /dev/cul0 -b 1200 X C-Kermit>set modem-dialer hayes hint: abbreviate set m h X C-Kermit>dial 9,5551212 X Connected! X C-Kermit>connect hint: abbreviate c X logon, request remote server, etc. X C-Kermit> ... X C-Kermit>quit hint: abbreviate q X Xthis disconnects modem, and unlocks line. X XExample two: X X kermit X C-Kermit>set modem-dialer ventel X C-Kermit>set line /dev/cul0 X C-Kermit>dial 9&5551212% X Connected! X C-Kermit> ... X XExample three: X X kermit X C-Kermit>take my-dial-procedure X Connected! X X file my-dial-procedure: X set modem hayes X set line /dev/tty99 X dial 5551212 X connect X XFor Hayes dialers, two important switch settings are #1 and #6. #1 should be Xup so that the DTR is only asserted when the line is 'open'. #6 should be up Xso carrier-detect functions properly. Switches #2 (English versus digit result Xcodes) and #4 (Hayes echoes modem commands) may be in either position. X X X THE 'SCRIPT' COMMAND: X XSyntax: script expect send [expect send] . . . X X"expect" has the syntax: expect[-send-expect[-send-expect[...]]] X XThis command facilitates logging into a remote system and/or invoking programs Xor other facilities after login on a remote system. X XThis login script facility operates in a manner similar to that commonly used Xby the Unix uucp System's "L.sys" file entries. A login script is a sequence Xof the form: X X expect send [expect send] . . . X Xwhere expect is a prompt or message to be issued by the remote site, and send Xis the string (names, numbers, etc) to return. The send may also be the Xkeyword EOT, to send Control-D, or BREAK, to send a break signal. Letters in Xsend may be prefixed by '~' to send special characters. These are: X X ~b backspace X ~s space X ~q '?'(trapped by Kermit's command interpreter) X ~n linefeed X ~r carriage return X ~t tab X ~' single quote X ~~ tilde X ~" double quote X ~c don't append a carriage return X ~o[o[o]] X an octal character X XAs with some uucp systems, sent strings are followed by ~r unless they have a X~c. X XOnly the last 7 characters in each expect are matched. A null expect, e.g. ~0 Xor two adjacent dashes, causes a short delay before proceeding to the next send Xsequence. A null expect always succeeds. X XAs with uucp, if the expect string does not arrive, the script attempt fails. XIf you expect that a sequence might not arrive, as with uucp, conditional se- Xquences may be expressed in the form: X X -send-expect[-send-expect[...]] X Xwhere dashed sequences are followed as long as previous expects fail. X XExpect/send transactions can be easily be debugged by logging transactions. XThis records all exchanges, both expected and actual. X XNote that '\' characters in login scripts, as in any other C-Kermit interactive Xcommands, must be doubled up. X XExample one: X XUsing a modem, dial a unix host site. Expect "login" (...gin), and if it Xdoesn't come, simply send a null string with a ~r. (Some Unixes require either Xan EOT or a BREAK instead of the null sequence, depending on the particular Xsite's "logger" program.) After providing user id and password, respond "x" to Xa question-mark prompt, expect the Bourne shell "$" prompt (and send return if Xit doesn't arrive). Then cd to directory kermit, and run the program called X"wermit", entering the interactive connect state after wermit is loaded. X X set modem-dialer ventel X set line /dev/tty77 X set baud 1200 X dial 9&5551212 X script gin:--gin:--gin: smith ssword: mysecret ~q x $--$ X cd~skermit $ wermit X connect X XExample two: X XUsing a modem, dial the Telenet network. This network expects three returns Xwith slight delays between them. These are sent following null expects. The Xsingle return is here sent as a null string, with a return appended by default. XFour returns are sent to be safe before looking for the prompt. Then the Xtelenet id and password are entered. Then telenet is instructed to connect to Xa host site (c 12345). The host has a data switch, and to "which system" it Xresponds "myhost". This is followed by a TOPS-20 logon, and a request to load XKermit, set even parity, and enter the server mode. Files are then exchanged. XThe commands are in a take file. The login command is split onto two lines for Xreadability, though it is a single long line in the take file. X X set modem-dialer hayes X set line /dev/cul0 X set baud 1200 X dial 9,5551212 X set parity even X script ~0 ~0 ~0 ~0 ~0 ~0 ~0 ~0 @--@--@ id~saa001122 = 002211 @ X c~s12345 ystem-c~s12345-ystem myhost @ joe~ssecret @ kermit X > set~sparity~seven > server X send some.stuff X get some.otherstuff X bye X quit X XSince these commands may be executed totally in the background, they can also Xbe scheduled. A typical shell script, which might be scheduled by cron, would Xbe as follows (csh used for this example): X # X #keep trying to dial and log onto remote host and exchange files X #wait 10 minutes before retrying if dial or script fail. X # X while ( 1 ) X kermit < tonight.cmd & X if ( ! $status ) break X sleep 600 X end X XFile tonight.cmd might have two takes in it, for example, one to take a file Xwith the set modem, set line, set baud, dial, and script, and a second take of Xa file with send/get commands for the remote server. The last lines of Xtonight.cmd should be a bye and a quit. X X X THE 'HELP' COMMAND: X XSyntax: help X or: help keyword X or: help {set, remote} keyword X XBrief help messages or menus are always available at interactive command level Xby typing a question mark at any point. A slightly more verbose form of help Xis available through the 'help' command. The 'help' command with no arguments Xprints a brief summary of how to enter commands and how to get further help. X'help' may be followed by one of the top-level C-Kermit command keywords, such Xas 'send', to request information about a command. Commands such as 'set' and X'remote' have a further level of help. Thus you may type 'help', 'help set', Xor 'help set parity'; each will provide a successively more detailed level of Xhelp. X X X THE 'EXIT' AND 'QUIT' COMMANDS: X XThese two commands are identical. Both of them do the following: X X - Attempt to insure that the terminal is returned to normal. X - Relinquish access to any communication line assigned via 'set line'. X - Close any open log files. X - Relinquish any uucp and multiuser locks on the communications line. X - Hang up the modem, if the communications line supports data terminal X ready. X XAfter exit from C-Kermit, your default directory will be the same as when you Xstarted the program. The 'exit' command is issued implicitly whenever C-Kermit Xhalts normally, e.g. after a command line invocation, or after certain kinds of Xinterruptions. X X X1.4. C-Kermit under Berkeley or System III/V Unix: X XC-Kermit may be interrupted at command level or during file transfer by typing XControl-C. The program will perform its normal exit function, restoring the Xterminal. If a protocol transaction was in progress, an error packet will be Xsent to the opposite Kermit so that it can terminate cleanly. X XC-Kermit may be invoked in the background ("&" on shell commmand line). If a Xbackground process is "killed", the user will have to manually remove any lock Xfile and may need to restore the modem. This is because the kill signal X(kill(x,9)) cannot be trapped by Kermit. X XDuring execution of a system command, C-Kermit can often be returned to command Xlevel by typing a single Control-C. (With System III/V, the usual interrupt Xfunction (often the DEL key) is replaced by Control-C.) On detecting XControl-C, C-Kermit takes its normal exit, removing lock files and restoring Xthe communication line, modem, and/or console terminal. X XUnder Berkeley Unix only: X C-Kermit may also be interrupted by ^Z to put the process in the back- X ground. In this case the terminal is not restored. You will have to type X Control-J followed by "reset" followed by another Control-J to get your X terminal back to normal. C-Kermit can be halted in a similar manner by X typing Control- X Backslash, except that instead of moving it to the background, a core dump X is produced. X XUnder System III/V Unix: X The Control-\ character (or whatever control character has been selected X via "set escape") at the C-Kermit command level is ignored; it is trapped X and will not core-dump or interrupt Kermit. X XControl-C, Control-Z, and Control-\ lose their normal functions during terminal Xconnection and also during file transfer when the controlling tty line is being Xused for packet i/o. X XThe BSD implementation of C-Kermit has code to take advantage of a special non- Xstandard kernel-mode line driver, which boosts the speed of packet i/o sig- Xnificantly. The problem is that "raw" mode, needed for packet i/o, also im- Xplies "cbreak" (character wakeup) mode, which is very expensive. The new line Xdriver is a modification of the "berknet" driver, which allowed raw mode i/o to Xtake place with process wakeup only upon receipt of a linefeed. The Berknet Xdriver, unfortunately, strips off the high order bit of each character and does Xnot allow the line terminator to be specified. The modification allows all 8 Xbits to pass through unmolested, allows the wakeup character to be specified, Xand allows the buffer to be tested or cleared. X XThe System III/V implementation uses regular kernel drivers, but "gulps" raw- Xmode input in large blocks, thus overcomming the usual system call overheads. X XIf you are running C-Kermit in "quiet mode" in the foreground, then interrupt- Xing the program with a console interrupt like Control-C will not restore the Xterminal to normal conversational operation. This is because the system call Xto enable console interrupt traps will cause the program to block if it's run- Xning in the background, and the primary reason for quiet mode is to allow the Xprogram to run in the background without blocking, so that you can do other Xwork in the foreground. X XIf C-Kermit is run in the background ("&" on shell commmand line), then the in- Xterrupt signal (Control-C) (and System III/V quit signal) are ignored. This Xprevents an interrupt signal intended for a foreground job (say a compilation) Xfrom being trapped by a background Kermit session. X X X1.5. C-Kermit on the DEC Pro-3xx with Venix 1.0 X XThe DEC Professional 300 series are PDP-11/23 based personal computers. Venix X1.0 is a Unix v7 derivative. It should not be confused with Venix 2.0, which Xresembles ATT System V. C-Kermit runs in local mode on the Pro-3xx when invoked Xfrom the console; the default device is /dev/com1. When connected to a remote Xsystem (using C-Kermit's 'connect' command), Pro/Venix itself (not Kermit) Xprovides VT52 terminal emulation. X XDuring file transfer, the interruption and status commands (Control-A, XControl-F, etc) are not available. X X X1.6. C-Kermit Restrictions and Known Bugs X X 1. File renaming: When filename collision avoidance ("warning") is X selected, C-Kermit constructs unique names by appending a generation X number to the end of the file name. Currently, no checking is done X to ensure that the result is still within the maximum length for a X file name. X X 2. UUCP line locking: C-Kermit locks lines, to prevent UUCP and mul- X tiuser conflicts, when it first opens a communications line. This X occurs either when 'set line' is issued, or if the '-l' argument is X used, when the first 'dial', 'connect', or protocol operation oc- X curs. The lock is released if another 'set line' is issued, or if X the program quits, exits, or is terminated by Control-C. If a user X connects and returns to the shell command level, for example to in- X itiate kermit by piped commands, on a communications line, the line X lock is released when returning to the shell. Locking is not X needed, or used, if communications occur over the local terminal X line (e.g. /dev/tty). In that case, there is no difficultly with X "piped" operations releasing locks and lines. X X 3. Removing stale lock files: For various reasons, lock files some- X times get left about after uucp or C-Kermit activities. (The most X common reason is that the uucp or C-Kermit activity was "killed" by X a shell command.) If the lock file is owned by yourself, clearly X you may remove it (presuming you are not running C-Kermit or uucp in X the background when you discovered it). X X Uucp supports a function, called uuclean, which is customarily used X to remove these files after a predetermined age. If in doubt about X a lock file on the dial-out line you need, contact your system's X operator. X X 4. Modem controls: If connection is made over a communication line X (rather than on the controlling terminal line), and that line has X modem controls, (e.g. data terminal ready and carrier detection X implementation), returning to the shell level will disconnect the X conversation. In that case, one should use interactive mode com- X mands, and avoid use of piped shell-level operation (also see 'set X modem-dialer' and 'dial' commands.) X X 5. Login Scripts: The present login scripts implementation follows the X Unix conventions of uucp's "L.sys" file, rather than the normal Ker- X mit "INPUT/OUTPUT" style. Volunteers have indicated an intent to X implement the Kermit standard for login scripts, and indeed even X others may be implemented in the future as needed. X X 6. Dial-out vs dial-in communications lines C-Kermit requires a X dial-out line for the "set line" or "-l" options. Most systems have X some lines dedicated to dial-in, which they enable "loggers" on, and X some lines available for dial-out. Where a line must be shared be- X tween dial-in and dial-out, several options are available (though X they are, strictly speaking, outside the pervue of C-Kermit). X X A simple shell program can be used to change directionality of the X line if your Unix has the enable(8) and disable(8) commands. In X that case, the shell program could "grep" a "who" to see if anybody X is logged onto the desired line; if not, it could "disable" the X line. The shell program will need to be set-uID'ed to root. The X shell program can be called from kermit prior to a dial command, X e.g., "! mydisable.shellprog". Prior to the final "quit" from X C-Kermit, another shell program could be executed to "enable" the X line again. This program also needs to be set-uID'ed to root. X X If your Unix lacks the enable(8) and disable(8) commands, another X common technique works if your system supports the /etc/ttys file. X A shell program could call up an awk program to find the line in the X file and set the enable byte to 0 (to directly disable the line). X Likewise, it can be reenabled by a counterpart at the end. It may X be necessary to pause for 60 seconds after modifying that file be- X fore the logger sees it and actually disables the line. X X 7. Using C-Kermit on Local Area Networks: C-Kermit can successfully X operate at speeds up to 9600 baud over LANs. Testing has, however, X shown that most processors, whether PC/XTs with PC/IX, or Vaxes, X need flow control at these rates. A command, "set flow x" should be X issued to each end of this form of connection. X X If the LAN is the sort with an interface card (or box, like the X Sytek), then the interface card/box must be programmed to handle the X flow control characters (xon and xoff) at the card/box level (rather X than forwarding these characters to the remote site). This is be- X cause packetizing LANs will not deliver the xoff character to the X other end, after packetization, until long after the receive buffer X has been overrun. X X 8. Resetting terminal after abnormal termination or kill: When C-Kermit X terminates abnormally (say, for example, by a kill command issued by X the operator) the user may need to reset the terminal state. If X commands do not seem to be accepted at the shell prompt, try X Control-J "stty sane" Control-J (use "reset" on Berkeley Unix). X That should take the terminal out of "raw mode" if it was stuck X there. X X 9. Remote host commands may time-out on lengthy activity: Using X "remote host" to instruct the C-Kermit server to invoke Unix func- X tions (like "make") that might take a long time to produce output X can cause timeout conditions. X X 10. PC/IX Login Scripts -- Unfound Bug: Though login scripts appear to X work properly on most processors, in the case of the PC/XT with X PC/IX, it appears that longer scripts need to be broken up into X shorter scripts (invoked sequentially from the take file). This is X because the portion of the script handler which checks if an opera- X tion timed out seems to leave the processor in a strange state (i.e. X hung). X X X1.7. How to Build C-Kermit for a Unix System X XThe C-Kermit files, as distributed from Columbia, all begin with the prefix X"ck". You should make a directory for these files and then cd to it. A Xmakefile is provided to build C-Kermit for various Unix systems. As dis- Xtributed, the makefile has the name "ckermi.mak". You should rename it to X"makefile" and then type "make xxx", where xxx is the symbol for your system, Xfor instance "make bsd" to make C-Kermit for 4.2 BSD Unix. The result will be Xa program called "wermit". You should test this to make sure it works; if it Xdoes, then you can rename it to "kermit" and install it for general use. See Xthe makefile for a list of the systems supported and the corresponding "make" Xarguments. X X X1.8. Adapting C-Kermit to Other Systems X XC-Kermit is designed for portability. The level of portability is indicated in Xparentheses after the module name: "C" means any system that has a C compiler Xthat conforms to the description in "The C Programming Language" by Kernighan & XRitchie (Prentice-Hall, 1978). "Cf" is like "C", but also requires "standard" Xfeatures like printf and fprintf, argument passing via argv/argc, and so on, as Xdescribed in Kernighan & Ritchie. "Unix" means the module should be useful un- Xder any Unix implementation; it requires features such as fork() and pipes. XAnything else means that the module is particular to the indicated system. The Xmodules are: X Xckmain.c, ckermi.h, ckdebu.h (Cf): X This is the main program. It contains declarations for global variables X and a small amount of code to initialize some variables and invoke the com- X mand parser. In its distributed form, it assumes that command line ar- X guments are passed to it via argc and argv. Since this portion of code is X only several lines long, it should be easy to replace for systems that have X different styles of user interaction. The header files define symbols and X macros used by the various modules of C-Kermit. ckdebu.h is the only X header file that is included by all the C-Kermit modules, so it contains X not only the debug format definitions, but also any system-dependent X typedefs. X Xwart.c (Cf), ckprot.w (C): X The ckprot module embodies the Kermit protocol state table and the code to X accomplish state switching. It is written in "wart", a language which may X be regarded as a subset of the Unix "lex" lexical analyzer generator. Wart X implements enough of lex to allow the ckprot module to function. Lex it- X self was not used because it is proprietary (but lex may be used in place X of wart with minor reformatting of ckprot.w -- removal of #includes and X comments, which must be reinserted into lex's output C program). The X protocol module ckprot.w is read by wart, and a system-independent C X program is produced. The syntax of a Wart program is illustrated by X ckprot.w, and is described in ckwart.doc. X Xckfns.c (C): X The module contains all the Kermit protocol support functions -- packet X formation, encoding, decoding, block check calculation, filename and data X conversion, protocol parameter negotiation, and high-level interaction with X the communication line and file system. To accommodate small systems, this X module has been split into two -- ckfns.c and ckfns2.c. X Xckx???.c (specific to system ???): X For instance, ckxunx.c (Berkeley, Venix, ATT System III/V, and other Unix X systems) -- The ckx module contains the system-dependent primitives for X communication line i/o, timers, and interrupts. Certain important vari- X ables are defined in this module, which determine whether C-Kermit is by X default remote or local, what the default communication device is, and so X forth. The ckx module maintains its own private database of file descrip- X tors and modes for the console terminal and the file transfer communication X line so that other modules (like ckfns or the terminal connect module) need X not be concerned with them. This module will vary significantly among Unix X implementations since the sgtty/ioctl/termio functions and their arguments X are among the least compatible areas of Unix. The ckxunx.c file has con- X ditional compilation for the variations of Unix. X Xckz???.c (specific to system ???): X For instance, ckzunx.c (Berkeley, Venix, System III/V Unix) -- The ckz X module contains system-dependent primitives for file i/o, wildcard (meta X character) expansion, file existence and access checking, and system com- X mand execution. It maintains an internal database of i/o "channels" (file X pointers in the case of Unix) for the files C-Kermit cares about -- the in- X put file (the file which is being sent), the output file (the file being X received), the various logs, the screen, and so forth. This module will X vary little among Unix implementations except for the wildcard expansion X code, which requires detailed knowledge of the directory structure. The X ckz module also defines variables containing the system command strings X used to perform certain functions like directory listing, file deletion, X etc. The ckzunx.c file has conditional compilation for the variations of X Unix. X Xckuser.h, ckuser.c, ckusr2.c, ckusr3.c (Unix): X This is the "user interface" for C-Kermit. It includes the command parser, X the screen output functions, and console input functions. The command par- X ser comes in two pieces -- the traditional Unix command line decoder (which X is quite small and compact), and the interactive keyword parser (which is X rather large). This module is fully replacable; its interface to the other X modules is very simple, and is explained at the beginning of the source X file. The ckuser module also includes code to execute any commands X directly which don't require the Kermit protocol -- local file management, X etc. The module is rated "Unix" because it makes occasional use of the X system() function. X X Note that while ckuser is logically one module, it has been split up into X three C source files, plus a header file for the symbols they share in com- X mon. This is to accommodate small systems that cannot handle big modules. X ckuser.c has the command line and top-level interactive command parser; X ckusr2.c has the help command and strings; ckusr3 has the set and remote X commands along with the logging, screen, and "interrupt" functions. X Xckcmd.c, ckcmd.h (Cf): X This is an interactive command parsing package developed for C-Kermit. It X is written portably enough to be usable on any system that has a C compiler X that supports functions like printf. The file name parsing functions X depend upon primitives defined in the ckz module; if these primitives can- X not be supplied for a certain system, then the filename parsing functions X can be deleted, and the package will still be useful for parsing keywords, X numbers, arbitrary text strings, and so forth. The style of interaction is X the same as that found on the DECSYSTEM-20. X Xckconu.c (Unix): X This is the connect module. As supplied, it should operate in any Unix en- X vironment, or any C-based environment that provides the fork() function. X The module requires access to global variables that specify line speed, X parity, duplex, flow control, etc, but invokes functions from the ckx X module to accomplish the desired settings and input/output, and functions X from the ckz module to perform session logging. There is no code for con- X trolling modem signals. No terminal emulation is performed, but since X standard i/o is used for the console, this may be piped through a terminal X emulation filter. The ckconu function may be entirely replaced, so long as X the global settings are honored by its replacement. PC implementations of X C-Kermit may require the ckcon module to do screen control, escape sequence X interpretation, etc, and may also wish to write special code to get the X best possible performance. X Xckdial.c (Unix): X This is the dialer module. As supplied, it handles hayes and ventel X modems. X Xcklogi.c (Unix): X This is the login script module. As supplied, it handles uucp-style X logins. X XMoving C-Kermit to a new system entails: X X 1. Creating a new ckx module in C, assembler, or whatever language is X most appropriate for system programming on the new system. X X 2. Creating a new ckz module, as above. X X 3. If the system is not Unix-like, then a new ckuser module may be re- X quired, as well as a different invocation of it from ckmain. X X 4. If the distributed connect module doesn't work or performs poorly, X then it may be replaced. For instance, interrupt-driven i/o may be X required, especially if the system doesn't have forks. X XThose who favor a different style of user/program interaction from that Xprovided in ckuser.c may replace the entire module, for instance with one that Xprovides a mouse/window/icon environment, a menu/function-key environment, etc. X XA few guidelines should be followed to maintain portability: X X - Keep variable and function names to 6 characters or less. X X - Keep modules small. For instance, on a PDP-11 it is necessary to X keep the code segment of each module below 8K in order to allow the X segment mapping to occur which is necessary to run programs larger X than 64K on a non-I-&-D-space machine. X X - Keep strings short; many compilers have restrictive maximum lengths. X X - Keep (f,s)printf arguments short. If these exceed some compiler de- X pendent maximum (perhaps as short as 128, after expansion) memory X will be overwritten and the program will probably core dump. X X - Do not introduce system dependencies into ckprot.w or ckfns*.c. X XIn general, remember that this program will have to be compilable by old com- Xpilers and runnable on small systems. X X X XIndex X X X C-Kermit 1 X X TELENET 6 X X Unix Kermit 1 X X X X Table of Contents X X1. UNIX KERMIT 1 X X 1.1. The Unix File System 1 X 1.2. Command Line Operation 1 X 1.3. Interactive Operation 3 X 1.4. C-Kermit under Berkeley or System III/V Unix: 7 X 1.5. C-Kermit on the DEC Pro-3xx with Venix 1.0 7 X 1.6. C-Kermit Restrictions and Known Bugs 7 X 1.7. How to Build C-Kermit for a Unix System 8 X 1.8. Adapting C-Kermit to Other Systems 8 X XIndex i !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckuser.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckuser.c Xchar *userv = "User Interface V4.2(038), 5 Mar 85"; X X/* C K U S E R -- "User Interface" for Unix Kermit (Part 1) */ X X/* Frank da Cruz, Columbia University Center for Computing Activities, 1985 */ X/* X The ckuser module contains the terminal input and output functions for Unix X Kermit. It includes a simple Unix-style command line parser as well as X an interactive prompting keyword command parser. It depends on the existence X of Unix facilities like fopen, fgets, feof, (f)printf, argv/argc, etc. Other X functions that are likely to vary among Unix implementations -- like setting X terminal modes or interrupts -- are invoked via calls to functions that are X defined in the system-dependent modules, ck[xz]*.c. X X The command line parser processes any arguments found on the command line, X as passed to main() via argv/argc. The interactive parser uses the facilities X of the cmd package (developed for this program, but usable by any program). X X Any command parser may be substituted for this one. The only requirements X for the Kermit command parser are these: X X 1. Set parameters via global variables like duplex, speed, ttname, etc. X See ckmain.c for the declarations and descriptions of these variables. X X 2. If a command can be executed without the use of Kermit protocol, then X execute the command directly and set the variable sstate to 0. Examples X include 'set' commands, local directory listings, the 'connect' command. X X 3. If a command requires the Kermit protocol, set the following variables: X X sstate string data X 'x' (enter server mode) (none) X 'r' (send a 'get' command) cmarg, cmarg2 X 'v' (enter receive mode) cmarg2 X 'g' (send a generic command) cmarg X 's' (send files) nfils, cmarg & cmarg2 OR cmlist X 'c' (send a remote host command) cmarg X X cmlist is an array of pointers to strings. X cmarg, cmarg2 are pointers to strings. X nfils is an integer. X X cmarg can be a filename string (possibly wild), or X a pointer to a prefabricated generic command string, or X a pointer to a host command string. X cmarg2 is the name to send a single file under, or X the name under which to store an incoming file; must not be wild. X cmlist is a list of nonwild filenames, such as passed via argv. X nfils is an integer, interpreted as follows: X -1: argument string is in cmarg, and should be expanded internally. X 0: stdin. X >0: number of files to send, from cmlist. X X The screen() function is used to update the screen during file transfer. X The tlog() function maintains a transaction log. X The debug() function maintains a debugging log. X The intmsg() and chkint() functions provide the user i/o for interrupting X file transfers. X*/ X X/* Includes */ X X#include "ckermi.h" X#include "ckcmd.h" X#include "ckuser.h" X X/* External Kermit Variables, see ckmain.c for description. */ X Xextern int size, spsiz, npad, timint, speed, local, server, image, flow, X displa, binary, fncnv, delay, parity, deblog, escape, xargc, X turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, stdouf, X turnch, chklen, bctr, bctu, fsize, dfloc, mdmtyp, X rptflg, ebqflg, warn, quiet, cnflg, timef, mypadn; X Xextern long filcnt, tlci, tlco, ffc, tfc; X Xextern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; Xextern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist; Xextern char mystch, sstate, mypadc, padch, eol, ctlq, filnam[], ttname[]; Xchar *strcpy(); X X/* Declarations from cmd package */ X Xextern char cmdbuf[]; /* Command buffer */ X X/* Declarations from ckz??? module */ X Xextern char *SPACMD, *zhome(); /* Space command, home directory. */ Xextern int backgrd; /* Kermit executing in background */ X X/* The background flag is set by ckxunx.c (via conint() ) to note whether */ X/* this kermit is executing in background ('&' on shell command line). */ X X X/* Variables and symbols local to this module */ X Xchar line[100], *lp; /* Character buffer for anything */ Xchar debfil[50]; /* Debugging log file name */ Xchar pktfil[50]; /* Packet log file name */ Xchar sesfil[50]; /* Session log file name */ Xchar trafil[50]; /* Transaction log file name */ X Xint n, /* General purpose int */ X cflg, /* Command-line connect cmd given */ X action, /* Action selected on command line*/ X ncmd, /* Number of commands */ X nprm, /* Number of parameters */ X nrmt, /* Number of remote commands */ X repars, /* Reparse needed */ X tlevel, /* Take command level */ X cwdf = 0; /* CWD has been done */ X X#define MAXTAKE 20 /* Maximum nesting of TAKE files */ XFILE *tfile[MAXTAKE]; /* File pointers for TAKE command */ X Xchar *homdir; /* Pointer to home directory string */ Xchar cmdstr[100]; X X/* C M D L I N -- Get arguments from command line */ X/* X Simple Unix-style command line parser, conforming with 'A Proposed Command X Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, X No.3, 1984. X*/ Xcmdlin() { X char x; X cmarg = ""; /* Initialize. */ X cmarg2 = ""; X action = cflg = 0; X X while (--xargc > 0) { /* Go through command line words */ X *xargv++; X debug(F111,"xargv",*xargv,xargc); X if (**xargv == '-') { /* Got an option (begins with dash) */ X x = *(*xargv+1); /* Get the option letter */ X x = doarg(x); /* Go handle the option */ X if (x < 0) exit(0); X } else { /* No dash where expected */ X usage(); X exit(1); X } X } X debug(F101,"action","",action); X if (!local) { X if ((action == 'g') || (action == 'r') || X (action == 'c') || (cflg != 0)) X fatal("-l and -b required"); X } X if (*cmarg2 != 0) { X if ((action != 's') && (action != 'r') && X (action != 'v')) X fatal("-a without -s, -r, or -g"); X } X if ((action == 'v') && (stdouf) && (!local)) { X if (isatty(1)) X fatal("unredirected -k can only be used in local mode"); X } X if ((action == 's') || (action == 'v') || X (action == 'r') || (action == 'x')) { X if (local) displa = 1; X if (stdouf) displa = 0; X } X X if (quiet) displa = 0; /* No display if quiet requested */ X X if (cflg) { X conect(); /* Connect if requested */ X if (action == 0) { X if (cnflg) conect(); /* And again if requested */ X doexit(0); /* exit with status = 0 */ X } X } X if (displa) concb(escape); /* (for console "interrupts") */ X return(action); /* Then do any requested protocol */ X} X X/* D O A R G -- Do a command-line argument. */ X Xdoarg(x) char x; { X int z; char *xp; X X xp = *xargv+1; /* Pointer for bundled args */ X while (x) { X switch (x) { X Xcase 'x': /* server */ X if (action) fatal("conflicting actions"); X action = 'x'; X break; X Xcase 'f': X if (action) fatal("conflicting actions"); X action = setgen('F',"","",""); X break; X Xcase 'r': /* receive */ X if (action) fatal("conflicting actions"); X action = 'v'; X break; X Xcase 'k': /* receive to stdout */ X if (action) fatal("conflicting actions"); X stdouf = 1; X action = 'v'; X break; X Xcase 's': /* send */ X if (action) fatal("conflicting actions"); X if (*(xp+1)) fatal("invalid argument bundling after -s"); X z = nfils = 0; /* Initialize file counter, flag */ X cmlist = xargv+1; /* Remember this pointer */ X while (--xargc > 0) { /* Traverse the list */ X *xargv++; X if (**xargv == '-') { /* Check for sending stdin */ X if (strcmp(*xargv,"-") != 0) break; X z++; X } X nfils++; /* Bump file counter */ X } X xargc++, *xargv--; /* Adjust argv/argc */ X if (nfils < 1) fatal("missing filename for -s"); X if (z > 1) fatal("-s: too many -'s"); X if (z == 1) { X if (nfils == 1) nfils = 0; X else fatal("invalid mixture of filenames and '-' in -s"); X } X if (nfils == 0) { X if (isatty(0)) fatal("sending from terminal not allowed"); X } X debug(F101,*xargv,"",nfils); X action = 's'; X break; X X/* cont'd... */ X X/* ...doarg(), cont'd */ X Xcase 'g': /* get */ X if (action) fatal("conflicting actions"); X if (*(xp+1)) fatal("invalid argument bundling after -g"); X *xargv++, xargc--; X if ((xargc == 0) || (**xargv == '-')) X fatal("missing filename for -g"); X cmarg = *xargv; X action = 'r'; X break; X Xcase 'c': /* connect before */ X cflg = 1; X break; X Xcase 'n': /* connect after */ X cnflg = 1; X break; X Xcase 'h': /* help */ X usage(); X return(-1); X Xcase 'a': /* "as" */ X if (*(xp+1)) fatal("invalid argument bundling after -a"); X *xargv++, xargc--; X if ((xargc < 1) || (**xargv == '-')) X fatal("missing name in -a"); X cmarg2 = *xargv; X break; X Xcase 'l': /* set line */ X if (*(xp+1)) fatal("invalid argument bundling after -l"); X *xargv++, xargc--; X if ((xargc < 1) || (**xargv == '-')) X fatal("communication line device name missing"); X strcpy(ttname,*xargv); X if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; X break; X Xcase 'b': /* set baud */ X if (*(xp+1)) fatal("invalid argument bundling"); X *xargv++, xargc--; X if ((xargc < 1) || (**xargv == '-')) X fatal("missing baud"); X z = atoi(*xargv); /* Convert to number */ X if (chkspd(z) > -1) speed = z; /* Check it */ X else fatal("unsupported baud rate"); X break; X Xcase 'i': /* Treat files as binary */ X binary = 1; X break; X X/* cont'd... */ X X/* ...doarg(), cont'd */ X X Xcase 'w': /* File warning */ X warn = 1; X break; X Xcase 'q': /* Quiet */ X quiet = 1; X break; X Xcase 'd': /* debug */ X debopn("debug.log"); X break; X Xcase 'p': /* set parity */ X if (*(xp+1)) fatal("invalid argument bundling"); X *xargv++, xargc--; X if ((xargc < 1) || (**xargv == '-')) X fatal("missing parity"); X switch(x = **xargv) { X case 'e': X case 'o': X case 'm': X case 's': parity = x; break; X case 'n': parity = 0; break; X default: fatal("invalid parity"); X } X break; X Xcase 't': X turn = 1; /* Line turnaround handshake */ X turnch = XON; /* XON is turnaround character */ X duplex = 1; /* Half duplex */ X flow = 0; /* No flow control */ X break; X Xdefault: X fatal("invalid argument, type 'kermit -h' for help"); X } X X x = *++xp; /* See if options are bundled */ X } X return(0); X} X X/* Misc */ X Xfatal(msg) char *msg; { /* Fatal error message */ X fprintf(stderr,"\r\nFatal: %s\n",msg); X tlog(F110,"Fatal:",msg,0l); X doexit(1); /* exit with status = 1 */ X} X X Xermsg(msg) char *msg; { /* Print error message */ X if (!quiet) fprintf(stderr,"\r\nError - %s\n",msg); X tlog(F110,"Error -",msg,0l); X} X X/* Interactive command parser */ X X X/* Top-Level Keyword Table */ X Xstruct keytab cmdtab[] = { X "!", XXSHE, 0, X "bye", XXBYE, 0, X "c", XXCON, CM_INV, X "close", XXCLO, 0, X "connect", XXCON, 0, X "cwd", XXCWD, 0, X "dial", XXDIAL, 0, X "directory", XXDIR, 0, X "echo", XXECH, 0, X "exit", XXEXI, 0, X "finish", XXFIN, 0, X "get", XXGET, 0, X "help", XXHLP, 0, X "log", XXLOG, 0, X "quit", XXQUI, 0, X "r", XXREC, CM_INV, X "receive", XXREC, 0, X "remote", XXREM, 0, X "s", XXSEN, CM_INV, X "script", XXLOGI, 0, X "send", XXSEN, 0, X "server", XXSER, 0, X "set", XXSET, 0, X "show", XXSHO, 0, X "space", XXSPA, 0, X "statistics", XXSTA, 0, X "take", XXTAK, 0 X}; Xint ncmd = (sizeof(cmdtab) / sizeof(struct keytab)); X X/* Parameter keyword table */ X Xstruct keytab prmtab[] = { X "baud", XYSPEE, CM_INV, X "block-check", XYCHKT, 0, X "delay", XYDELA, 0, X "duplex", XYDUPL, 0, X "end-of-packet", XYEOL, 0, X "escape-character", XYESC, 0, X "file", XYFILE, 0, X "flow-control", XYFLOW, 0, X "handshake", XYHAND, 0, X "line", XYLINE, 0, X "modem-dialer", XYMODM, 0, X "packet-length", XYLEN, 0, X "pad-character", XYPADC, 0, X "padding", XYNPAD, 0, X "parity", XYPARI, 0, X "prompt", XYPROM, 0, X "speed", XYSPEE, 0, X "start-of-packet", XYMARK, 0, X "timeout", XYTIMO, 0 X}; Xint nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */ X X X/* Remote Command Table */ X Xstruct keytab remcmd[] = { X "cwd", XZCWD, 0, X "delete", XZDEL, 0, X "directory", XZDIR, 0, X "help", XZHLP, 0, X "host", XZHOS, 0, X "space", XZSPA, 0, X "type", XZTYP, 0, X "who", XZWHO, 0 X}; Xint nrmt = (sizeof(remcmd) / sizeof(struct keytab)); X Xstruct keytab logtab[] = { X "debugging", LOGD, 0, X "packets", LOGP, 0, X "session", LOGS, 0, X "transactions", LOGT, 0 X}; Xint nlog = (sizeof(logtab) / sizeof(struct keytab)); X X/* Show command arguments */ X X#define SHPAR 0 /* Parameters */ X#define SHVER 1 /* Versions */ X Xstruct keytab shotab[] = { X "parameters", SHPAR, 0, X "versions", SHVER, 0 X}; X X/* C M D I N I -- Initialize the interactive command parser */ X Xcmdini() { X X printf("%s,%s\nType ? for help\n",versio,ckxsys); X cmsetp("C-Kermit>"); /* Set default prompt. */ X X tlevel = -1; /* Take file level */ X X/* Look for init file ".kermrc" in home or current directory. */ X X homdir = zhome(); X lp = line; X if (homdir) X sprintf(lp,"%s/.kermrc",homdir); X else X sprintf(lp,".kermrc"); X if ((tfile[0] = fopen(line,"r")) != NULL) { X tlevel = 0; X debug(F110,"init file",line,0); X } X if (homdir && (tlevel < 0)) { X sprintf(lp,".kermrc"); X if ((tfile[0] = fopen(line,"r")) != NULL) { X tlevel = 0; X debug(F110,"init file",line,0); X } else { X debug(F100,"no init file","",0); X } X } X X congm(); /* Get console tty modes */ X} X X X/* T R A P -- Terminal interrupt handler */ X Xtrap() { X debug(F100,"terminal interrupt...","",0); X doexit(0); /* exit with status = 0 */ X} X X/* P A R S E R -- Top-level interactive command parser. */ X Xparser() { X int xx; X concb(escape); /* Put console in cbreak mode. */ X conint(trap); /* Turn on console terminal interrupts. */ X/* X sstate becomes nonzero when a command has been parsed that requires some X action from the protocol module. Any non-protocol actions, such as local X directory listing or terminal emulation, are invoked directly from below. X*/ X if (local) printf("\n"); /*** Temporary kludge ***/ X sstate = 0; /* Start with no start state. */ X while (sstate == 0) { /* Parse cmds until action requested */ X while ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */ X fclose(tfile[tlevel]); /* file, close it */ X tlevel--; /* and forget about it. */ X cmini(ckxech); /* and clear the cmd buffer. */ X } X if (tlevel > -1) { X if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL) continue; X stripq(cmdbuf); /* Strip any quotes. */ X } else { /* Otherwise. */ X prompt(); /* Issue interactive prompt. */ X cmini(ckxech); X } X repars = 1; X displa = 0; X while (repars) { X cmres(); /* Reset buffer pointers. */ X xx = cmkey(cmdtab,ncmd,"Command",""); X debug(F101,"top-level cmkey","",xx); X switch (docmd(xx)) { X case -4: /* EOF */ X doexit(0); /* exit with status 0 */ X case -1: /* Reparse needed */ X repars = 1; X continue; X case -2: /* Invalid command given */ X if (backgrd) /* if in background, terminate */ X fatal("Kermit command error in background execution"); X if (tlevel > -1) { /* If in take file, quit */ X ermsg("Kermit command error: take file terminated."); X fclose(tfile[tlevel]); X tlevel--; X } X cmini(ckxech); /* (fall thru) */ X case -3: /* Empty command OK at top level */ X default: /* Anything else (fall thru) */ X repars = 0; /* No reparse, get new command. */ X continue; X } X } X } X/* Got an action command; disable terminal interrupts and return start state */ X X if (!local) connoi(); /* Interrupts off only if remote */ X return(sstate); X} X X/* D O E X I T -- Exit from the program. */ X Xdoexit(exitstat) int exitstat; { X X ttclos(); /* Close external line, if any */ X if (local) { X strcpy(ttname,dftty); /* Restore default tty */ X local = dfloc; /* And default remote/local status */ X } X if (!quiet) conres(); /* Restore console terminal. */ X if (!quiet) connoi(); /* Turn off console interrupt traps. */ X X if (deblog) { /* Close any open logs. */ X debug(F100,"Debug Log Closed","",0); X *debfil = '\0'; X deblog = 0; X zclose(ZDFILE); X } X if (pktlog) { X *pktfil = '\0'; X pktlog = 0; X zclose(ZPFILE); X } X if (seslog) { X *sesfil = '\0'; X seslog = 0; X zclose(ZSFILE); X } X if (tralog) { X tlog(F100,"Transaction Log Closed","",0l); X *trafil = '\0'; X tralog = 0; X zclose(ZTFILE); X } X exit(exitstat); /* Exit from the program. */ X} X X/* B L D L E N -- Make length-encoded copy of string */ X Xchar * Xbldlen(str,dest) char *str, *dest; { X int len; X len = strlen(str); X *dest = tochar(len); X strcpy(dest+1,str); X return(dest+len+1); X} X X X/* S E T G E N -- Construct a generic command */ X Xsetgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; { X char *upstr, *cp; X X cp = cmdstr; X *cp++ = type; X *cp = NUL; X if (*arg1 != NUL) { X upstr = bldlen(arg1,cp); X if (*arg2 != NUL) { X upstr = bldlen(arg2,upstr); X if (*arg3 != NUL) bldlen(arg3,upstr); X } X } X cmarg = cmdstr; X debug(F110,"setgen",cmarg,0); X X return('g'); X} X X/* D O C M D -- Do a command */ X X/* X Returns: X -2: user typed an illegal command X -1: reparse needed X 0: parse was successful (even tho command may have failed). X*/ X Xdocmd(cx) int cx; { X int x, y; X char *s; X X switch (cx) { X Xcase -4: /* EOF */ X if (!quiet) printf("\r\n"); X doexit(0); Xcase -3: /* Null command */ X return(0); Xcase -2: /* Error */ Xcase -1: /* Reparse needed */ X return(cx); X Xcase XXBYE: /* bye */ X if ((x = cmcfm()) < 0) return(x); X if (!local) { X printf("You have to 'set line' first\n"); X return(0); X } X sstate = setgen('L',"","",""); X return(0); X Xcase XXCON: /* connect */ X if ((x = cmcfm()) < 0) return(x); X conres(); /* restore tty to normal mode */ X x = conect(); X concb(escape); /* tty back in character mode */ X return(x); X Xcase XXCWD: X if (cmtxt("Name of local directory, or carriage return",homdir,&s) < 0) X return(-1); X if (chdir(s)) perror(s); X cwdf = 1; X system("pwd"); X return(0); X Xcase XXCLO: X x = cmkey(logtab,nlog,"Which log to close",""); X if (x == -3) { X printf("?You must tell which log\n"); X return(-2); X } X if (x < 0) return(x); X if ((y = cmcfm()) < 0) return(y); X switch (x) { X X case LOGD: X if (deblog == 0) { X printf("?Debugging log wasn't open\n"); X return(0); X } X *debfil = '\0'; X deblog = 0; X return(zclose(ZDFILE)); X X case LOGP: X if (pktlog == 0) { X printf("?Packet log wasn't open\n"); X return(0); X } X *pktfil = '\0'; X pktlog = 0; X return(zclose(ZPFILE)); X X case LOGS: X if (seslog == 0) { X printf("?Session log wasn't open\n"); X return(0); X } X *sesfil = '\0'; X seslog = 0; X return(zclose(ZSFILE)); X X case LOGT: X if (tralog == 0) { X printf("?Transaction log wasn't open\n"); X return(0); X } X *trafil = '\0'; X tralog = 0; X return(zclose(ZTFILE)); X X default: X printf("\n?Unexpected log designator - %ld\n", x); X return(0); X } X Xcase XXDIAL: /* dial number */ X if ((x = cmtxt("Number to be dialed","",&s)) < 0) return(x); X return( dial(s) ); /* return success 0=connected -2=fail*/ X Xcase XXDIR: /* directory */ X if ((x = cmtxt("Directory/file specification","*",&s)) < 0) return(x); X lp = line; X sprintf(lp,"ls -l %s",s); X system(line); X return(0); X Xcase XXECH: /* echo */ X x = cmtxt("Material to be echoed","",&s); X if (x < 0) return(x); X printf("%s\n",s); X return(0); X Xcase XXQUI: /* quit, exit */ Xcase XXEXI: X if ((x = cmcfm()) > -1) doexit(0); /* exit with status 0 */ X else return(x); X Xcase XXFIN: /* finish */ X if ((x = cmcfm()) < 0) return(x); X if (!local) { X printf("You have to 'set line' first\n"); X return(0); X } X sstate = setgen('F',"","",""); X return(0); X Xcase XXGET: /* Get */ X if (!local) { X printf("\nYou have to 'set line' first\n"); X return(0); X } X x = cmtxt("Name of remote file(s), or carriage return","",&cmarg); X if ((x == -2) || (x == -1)) return(x); X X/* If foreign file name omitted, get foreign and local names separately */ X X if (*cmarg == NUL) { X X if (tlevel > -1) { /* Input is from take file */ X X if (fgets(line,100,tfile[tlevel]) == NULL) X fatal("take file ends prematurely in 'get'"); X stripq(line); X cmarg = line; X if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL) X fatal("take file ends prematurely in 'get'"); X stripq(cmdbuf); X if (*cmdbuf == NUL) cmarg2 = line; else cmarg2 = cmdbuf; X X } else { /* Input is from terminal */ X X char psave[40]; /* Save old prompt */ X cmsavp(psave,40); X cmsetp(" Remote file specification: "); /* Make new one */ X cmini(ckxech); X x = -1; X while (x < 0) { /* Prompt till they answer */ X prompt(); X x = cmtxt("Name of remote file(s)","",&cmarg); X if (*cmarg == NUL) x = -1; X } X strcpy(line,cmarg); /* Make a safe copy */ X cmarg = line; X cmsetp(" Local name to store it under: "); /* New prompt */ X cmini(ckxech); X x = -1; X while (x < 0) { /* Again, prompt till answered */ X prompt(); X x = cmofi("Local file name",cmarg,&cmarg2); X if (x == -2) return(x); X } X cmsetp(psave); /* Restore old prompt. */ X if ((x == cmcfm()) < 0) return(-2); X } X } X sstate = 'r'; /* All ok, set start state. */ X if (local) displa = 1; X return(0); X Xcase XXHLP: /* Help */ X x = cmkey(cmdtab,ncmd,"C-Kermit command","help"); X return(dohlp(x)); X Xcase XXLOG: /* Log */ X x = cmkey(logtab,nlog,"What to log",""); X if (x == -3) { X printf("?You must specify what is to be logged\n"); X return(-2); X } X if (x < 0) return(x); X return(dolog(x)); X Xcase XXLOGI: /* login to remote system */ X if ((x = cmtxt("Text of login script","",&s)) < 0) return(x); X return( login(s) ); /* return success 0=completed -2=fail*/ X Xcase XXREC: /* Receive */ X cmarg2 = ""; X x = cmofi("Name under which to store the file, or CR","",&cmarg2); X if ((x == -1) || (x == -2)) return(x); X debug(F111,"cmofi cmarg2",cmarg2,x); X if ((x = cmcfm()) < 0) return(x); X sstate = 'v'; X if (local) displa = 1; X return(0); X Xcase XXREM: /* Remote */ X if (!local) { X printf("\nYou have to 'set line' first\n"); X return(-2); X } X x = cmkey(remcmd,nrmt,"Remote Kermit server command",""); X if (x == -3) { X printf("?You must specify a command for the remote server\n"); X return(-2); X } X return(dormt(x)); X Xcase XXSEN: /* Send */ X cmarg = cmarg2 = ""; X if ((x = cmifi("File(s) to send","",&s,&y)) < 0) { X if (x == -3) { X printf("?A file specification is required\n"); X return(-2); X } X return(x); X } X nfils = -1; /* Files come from internal list. */ X strcpy(line,s); /* Save copy of string just parsed. */ X debug(F101,"Send: wild","",y); X *cmarg2 = '\0'; /* Initialize send-as name */ X if (y == 0) { X if ((x = cmfld("Name to send it with",line,&cmarg2)) < 0) return(x); X } X if ((x = cmcfm()) < 0) return(x); X cmarg = line; /* File to send */ X debug(F110,"Sending:",cmarg,0); X debug(F110," as:",cmarg2,0); X sstate = 's'; /* Set start state */ X if (local) displa = 1; X return(0); X Xcase XXSER: /* Server */ X if (x = (cmcfm()) < 0) return(x); X sstate = 'x'; X if (local) displa = 1; X return(0); X Xcase XXSET: /* Set */ X x = cmkey(prmtab,nprm,"Parameter",""); X if (x == -3) { X printf("?You must specify a parameter to set\n"); X return(-2); X } X if (x < 0) return(x); X return(doprm(x)); X Xcase XXSHE: /* Local shell command */ X if (cmtxt("Unix shell command to execute","",&s) < 0) return(-1); X conres(); /* Make console normal */ X system(s); /* Execute the command */ X concb(escape); /* Console back in cbreak mode */ X return(0); X Xcase XXSHO: /* Show */ X x = cmkey(shotab,2,"","parameters"); X if (x < 0) return(x); X if (y = (cmcfm()) < 0) return(y); X switch (x) { X X case SHPAR: X shopar(); X break; X X case SHVER: X printf("\nVersions:\n %s\n %s\n %s\n",versio,protv,fnsv); X printf(" %s\n %s\n %s for%s\n",cmdv,userv,ckxv,ckxsys); X printf(" %s for%s\n %s\n\n",ckzv,ckzsys,connv); X break; X X default: X printf("\nNothing to show...\n"); X break; X } X return(0); X Xcase XXSPA: /* space */ X if (x = (cmcfm()) < 0) return(x); X system(SPACMD); X return(0); X Xcase XXSTA: /* statistics */ X if (x = (cmcfm()) < 0) return(x); X printf("\nMost recent transaction --\n"); X printf(" files: %ld\n",filcnt); X printf(" total file characters : %ld\n",tfc); X printf(" communication line in : %ld\n",tlci); X printf(" communication line out : %ld\n\n",tlco); X printf(" block check type used : %d\n",bctu); X printf(" compression : "); X if (rptflg) printf("yes\n"); else printf("no\n"); X printf(" 8th bit prefixing : "); X if (ebqflg) printf("yes\n"); else printf("no\n\n"); X return(0); X Xcase XXTAK: /* take */ X if (tlevel > MAXTAKE-1) { X printf("?Take files nested too deeply\n"); X return(-2); X } X if ((y = cmifi("C-Kermit command file","",&s,&x)) < 0) { X if (y == -3) { X printf("?A file specification is required\n"); X return(-2); X } else return(y); X } X if (x != 0) { X printf("?Wildcards not allowed in command file name\n"); X return(-2); X } X strcpy(line,s); /* Make a safe copy of the string */ X if ((y = cmcfm()) < 0) return(y); X if ((tfile[++tlevel] = fopen(line,"r")) == NULL) { X perror("take"); X printf("Can't open command file - %s\n",line); X debug(F110,"Failure to open",line,0); X tlevel--; X return(0); X } X return(0); X Xdefault: X printf("Not available yet - %s\n",cmdbuf); X return(-2); X } X} X X/* S H O P A R -- Show Parameters */ X Xshopar() { X X printf("\nLine: %s, speed: %d, mode: ",ttname,speed); X if (local) printf("local"); else printf("remote"); X printf(", modem-dialer: "); X if (mdmtyp == 1) printf("hayes"); X else if (mdmtyp == 2) printf("ventel"); X else printf("direct"); X printf("\n Parity: "); X switch (parity) { X case 'e': printf("even"); break; X case 'o': printf("odd"); break; X case 'm': printf("mark"); break; X case 's': printf("space"); break; X case 0: printf("none"); break; X default: printf("invalid - %d",parity); break; X } X printf(", duplex: "); X if (duplex) printf("half, "); else printf("full, "); X printf("flow: "); X if (flow == 1) printf("xon/xoff"); X else if (flow == 0) printf("none"); X else printf("%d",flow); X printf(", handshake: "); X if (turn) printf("%d\n",turnch); else printf("none\n"); X printf(" Timeout: %d, delay: %d\n",timint,delay); X printf(" Padding: %d, pad character: %d\n",mypadn,mypadc); X printf(" Packet start: %d, end: %d, length: %d",mystch,eol,spsiz); X printf(", block check: %d\n",bctr); X printf("\nFile parameters:\n"); X printf(" Names: "); X if (fncnv) printf("converted\n"); else printf("literal\n"); X printf(" Type: "); X if (binary) printf("binary\n"); else printf("text\n"); X printf(" Warning: "); X if (warn) printf("on\n"); else printf("off\n"); X printf(" Display: "); X if (quiet) printf("off\n"); else printf("on\n"); X printf("\nLogs:"); X printf("\n Debugging: "); X if (deblog) printf("%s",debfil); else printf("none"); X printf("\n Packets: "); X if (pktlog) printf("%s",pktfil); else printf("none"); X printf("\n Session: "); X if (seslog) printf("%s",sesfil); else printf("none"); X printf("\n Transactions: "); X if (tralog) printf("%s",trafil); else printf("none"); X printf("\n\n"); X} X X/* D O L O G -- */ X Xdolog(x) int x; { X int y; char *s; X X switch (x) { X X case LOGD: X y = cmofi("Name of debugging log file","debug.log",&s); X break; X X case LOGP: X y = cmofi("Name of packet log file","packet.log",&s); X break; X X case LOGS: X y = cmofi("Name of session log file","session.log",&s); X break; X X case LOGT: X y = cmofi("Name of transaction log file","transaction.log",&s); X break; X X default: X printf("\n?Unexpected log designator - %d\n",x); X return(-2); X } X if (y < 0) return(y); X X strcpy(line,s); X s = line; X if ((y = cmcfm()) < 0) return(y); X X/* cont'd... */ X X/* ...dolog, cont'd */ X X X switch (x) { X X case LOGD: X return(deblog = debopn(s)); X X case LOGP: X zclose(ZPFILE); X y = zopeno(ZPFILE,s); X if (y > 0) strcpy(pktfil,s); else *pktfil = '\0'; X return(pktlog = y); X X case LOGS: X zclose(ZSFILE); X y = zopeno(ZSFILE,s); X if (y > 0) strcpy(sesfil,s); else *sesfil = '\0'; X return(seslog = y); X X case LOGT: X zclose(ZTFILE); X tralog = zopeno(ZTFILE,s); X if (tralog > 0) { X strcpy(trafil,s); X tlog(F110,"Transaction Log:",versio,0l); X tlog(F100,ckxsys,"",0); X ztime(&s); X tlog(F100,s,"",0l); X } X else *trafil = '\0'; X return(tralog); X X default: X return(-2); X } X} X X X/* D E B O P N -- Open a debugging file */ X Xdebopn(s) char *s; { X char *tp; X zclose(ZDFILE); X deblog = zopeno(ZDFILE,s); X if (deblog > 0) { X strcpy(debfil,s); X debug(F110,"Debug Log ",versio,0); X debug(F100,ckxsys,"",0); X ztime(&tp); X debug(F100,tp,"",0); X } else *debfil = '\0'; X return(deblog); X} X !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckcmd.h sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckcmd.h X/* C K C M D . H -- Header file for cmd package */ X X/* Sizes of things */ X X#define HLPLW 78 /* Width of ?-help line */ X#define HLPCW 19 /* Width of ?-help column */ X#define CMDBL 200 /* Command buffer length */ X#define HLPBL 100 /* Help string buffer length */ X#define ATMBL 100 /* Command atom buffer length*/ X X/* Special characters */ X X#define NUL '\0' /* Null */ X#define HT '\t' /* Horizontal Tab */ X#define NL '\n' /* Newline */ X#define FF 0014 /* Formfeed (^L) */ X#define RDIS 0022 /* Redisplay (^R) */ X#define LDEL 0025 /* Delete line (^U) */ X#define WDEL 0027 /* Delete word (^W) */ X#define ESC 0033 /* Escape */ X#define RUB 0177 /* Rubout */ X X#ifndef BEL X#define BEL 0007 /* Bell */ X#endif X X#ifndef BS X#define BS 0010 /* Backspace */ X#endif X X#ifndef SP X#define SP 0040 /* Space */ X#endif X X/* Keyword table flags */ X X#define CM_INV 1 /* Invisible keyword */ X X/* Keyword Table Template */ X Xstruct keytab { /* Keyword table */ X char *kwd; /* Pointer to keyword string */ X int val; /* Associated value */ X int flgs; /* Flags (as defined above) */ X}; !FUNKY!STUFF! echo x - ckdebu.h sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckdebu.h X/* C K D E B U . H */ X X/* X This file is included by all C-Kermit modules, including the modules X that aren't specific to Kermit (like the command parser and the ck[xz]* X modules. It specifies format codes for debug(), tlog(), and similar X functions, and includes any necessary typedefs. X*/ X X#define F000 0 /* Formats for debug() */ X X#define F001 1 X#define F010 2 X#define F011 3 X#define F100 4 X#define F101 5 X#define F110 6 X#define F111 7 X X/* Compiler dependencies */ X X#ifdef PROVX1 Xtypedef char CHAR; Xtypedef long LONG; Xtypedef int void; X#else Xtypedef unsigned char CHAR; Xtypedef unsigned long LONG; X#endif !FUNKY!STUFF! echo x - ckermi.ann sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.ann X 5-Feb-85 16:10:21-EST,5392;000000000001 XMail-From: SY.FDC created at 5-Feb-85 16:09:41 XDate: Tue 5 Feb 85 16:09:41-EST XFrom: Frank da Cruz <SY.FDC@CU20B.ARPA> XSubject: Info-Kermit Digest V2 #1 -- New Unix Kermit XTo: Info-Kermit-Members@CU20B.ARPA Xcc: Info-Unix@BRL-TGR.ARPA XReply-To: Info-Kermit@CU20B XQueries-To: Info-Kermit-Request@CU20B X XInfo-Kermit Digest Tue, 5 Feb 1985 Volume 2 : Number 1 X X ANNOUNCEMENTS - X New Unix Kermit Available for Testing X X---------------------------------------------------------------------- X XMy apologies for the long delay since the last issue of the Info-Kermit XDigest, which was Vol.1, No.46, dated 31 December 1984. This first issue Xof Volume 2 is to announce a test release of the new Unix Kermit. In Xsubsequent issues, I'll attempt to catch up on other overdue items. X XA new Kermit program has been written in C, initially for 4.2 Berkeley Unix. XThe features of this program include: X X. Full implementation of the Kermit protocol, except for Attribute packets: X - Acts as server X - Talks to server X - All packet encoding and error checking options are provided X - File transfer interruption X - Filename collision avoidance X - Binary and text file transfer X. Modular construction for easy portability to other systems X. An interactive command parser as well as Unix-style command line arguments X. Command and initialization files X. Piped operation X. Improved terminal connect, with optional logging X. Logs for debugging, packets, and transactions X. Communication with IBM mainframes X XSeveral items on the wish list were not done for lack of time. They will Xprobably be added in the future: X X. File attributes X. Command macros X. Login scripts X. Raw file transmit X XThe new program is called "C-Kermit" because it is intended as a basis for XKermit programs for any systems that have C compilers. Its version number Xis 4.0, to distinguish it from earlier releases of Unix Kermit, the most Xrecent of which was 3.0. X XThis prerelease test version of the program runs only under Berkeley Unix 4.2. XWe also intend to bring it to the following systems within the coming weeks: X X. DEC Pro-350 and Pro-380 with Venix (a Unix v7 derivative) X. Amdahl UTS on IBM 370-series mainframes X. Apple Macintosh (maybe) X XSupport for other systems will have to be added elsewhere. The program is Xbeing "pre-released" at this time for two reasons: X X1. It seems to be perfectly usable on Berkeley 4.2 systems, and is an X improvement over the previous version. X X2. The modular design may need some adjustment to accommodate certain systems. X Before a great deal of additional coding is done, it is highly desirable X to get the design and specification of the system-dependent modules stable. X XTherefore, please take the files, read the documentation, try running the Xprogram on your Berkeley Unix system if you have one, and send comments or bug Xreports to me as soon as you can. If you have a Unix system that is not XBerkeley Unix, or a non-Unix system with a C compiler, please take a look at Xthe system-dependent modules to see how they could be adapted to your system; Xagain, if you have any suggestions or criticisms of the design, please let me Xknow. I'm particularly interested in issues of portability. After a round or Xtwo of this, perhaps the design can be agreed upon, and then those who would Xlike to contribute support for Version 6, System III, System V, Xenix, PC/IX, Xetc etc, can do so without fear of running into other people's changes for Xother systems. Before attempting to adapt C-Kermit to a new system, please Xlet me know so I can tell you whether someone else is already at work on the Xsame thing, and perhaps put you in touch. X XThe files are on CU20B as KER:CK*.*, available via anonymous FTP. The file XCKERMI.DOC provides user-level documentation as well as a description of the Xprogram organization and hints for adapting it to new systems. Within several Xdays the files should also be available on BITNET via KERMSRV (to get started Xwith KERMSRV, type SMSG RSCS MSG CUVMA KERMSRV HELP), and to Unix systems via XUUCP from Oklahoma State University, Stillwater, OK. X XHere's how to UUCP to OK State: X XYou need to set up "okstate" as a site in your "L.sys" UUCP dialing file Xusing the information listed below. You can then issue the following Xcommand on your system: X X uucp okstate\!/u/kermit/ck\* /usr/spool/uucppublic X X (this example will retrieve the new Unix version of Kermit) X XThe "/usr/spool/uucppublic" is chosen as the destination on your system since Xthe destination must be WIDE OPEN (drwxrwxrwx) to everyone. You should Xnot remove files from your uucppublic until the entire transfer is complete Xincluding any redials that are necessary. If you do remove some files Xour system may retransmit them, resulting in a higher phone bill for you. X X-- UUCP Login information -- X XSite Name : okstate XPhone number : (405) 624-6953 (one line only) XLogin name : uucpker XPassword : thefrog XHours : 10:00pm - 10:00am central time (7 day per week) XProblem : okstate!uucp-support (UUCP) X reports : uucp-support%okstate@csnet-relay (ARPA) X XThe phone number is for 300/1200 baud (bell compatible). X X------------------------------ X XEnd of Info-Kermit Digest X************************* X------- XFrom columbia!SY.FDC@CU20B.DECNET Wed Mar 6 22:17:55 1985 XReceived: by cucca.UUCP (4.12/4.7) X id AA24373; Wed, 6 Mar 85 22:17:55 est XReceived: from CU20B.ARPA by columbia.arpa; Wed, 6 Mar 85 21:44:26 est XDate: Wed 6 Mar 85 21:53:20-EST XFrom: Frank da Cruz <columbia!SY.FDC@CU20B.DECNET> XSubject: Info-Kermit Digest V2 #9, C-Kermit Release #2 XTo: Info-Kermit@CU20B.DECNET, Info-Micro@BRL-VGR.ARPA, Info-Unix@BRL.ARPA XReply-To: Info-Kermit@CU20B XQueries-To: Info-Kermit-Request@CU20B X XInfo-Kermit Digest Wed, 6 Mar 1985 Volume 2 : Number 9 X X Second Pre-Release of C-Kermit for Unix X X---------------------------------------------------------------------- X XDate: Wed 6 Mar 85 21:43:12-EST XFrom: Frank da Cruz <SY.FDC@CU20B> XSubject: Second Pre-Release of C-Kermit for Unix XTo: Info-Kermit@CU20B X XThis is to announce the second "pre-release" of C-Kermit. The first Xpre-release (version 4.0) occurred a month ago; the program included Xsupport only for Berkeley Unix. This new release (4.2) includes support Xfor: X X. 4.x Berkeley Unix (VAX, SUN) X. Generic AT&T System III, System V X. Microsoft Xenix for the PC/AT X. Interactive on the PC/XT (PC/IX) and other systems X. DEC Professional 3xx with Venix 1.0 X. NCR Tower X XAll reported bugs have been fixed (or at least fixes have been Xattempted), and many of the restrictions lifted. "Dial" and "script" Xcommands have been added, along with code to support modem control and Xdialers, uucp line locking, and the like. The program itself has been Xsomewhat reorganized to be more adaptable to small environments: the Xlarger modules have been split; long character strings have been Xshortened. X XMost of the new work was done by Herm Fischer of Litton Data Systems, Van XNuys CA (HFISCHER@USC-ISIB), and there were also contributions from many Xothers in the form of bug reports and/or fixes. NCR Tower support came Xfrom John Bray at Auburn University. The new makefile (distributed as XCKERMI.MAK) embodies procedures for building all the different versions. X XSince the program now runs on a variety computers, large and small, it Xwould seem relatively safe to begin adding support for other systems Xwithout fear that the program will have to be completely reorganized X(again). The only systems supported by C-Kermit so far are Unix systems; Xrather than create a separate ckx and ckz module for each such system X(since these systems tend to differ in small places, but still have much Xin common), conditional compilation was used within these modules. If XC-Kermit is to be adapted to non-Unix systems, then a full replacement of Xthe ckx and/or ckz modules is probably indicated. This is what we will Xprobably do in bringing the program up on the Macintosh. X XThe files are available via anonymous FTP from Internet host CU20B X(Internet number 192.5.43.128) as KER:CK*.*. They will appear at Xokstate (for uucp'ing) and on KERMSRV (BITnet) shortly. If you plan to Xadapt this program to a new system, be sure to let me know quickly so I Xcan prevent duplication of effort and can put people with similar Xinterests in touch with each other. X X------------------------------ X XEnd of Info-Kermit Digest X************************* X------- !FUNKY!STUFF! echo x - ckermi.h sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.h X/* ckermit.h -- Symbol and macro definitions for C-Kermit */ X X#include <stdio.h> X#include <ctype.h> X#include "ckdebu.h" X X/* Mnemonics for ASCII characters */ X X#define SOH 001 /* ASCII Start of header */ X#define BEL 007 /* ASCII Bell (Beep) */ X#define BS 010 /* ASCII Backspace */ X#define CR 015 /* ASCII Carriage Return */ X#define XON 021 /* ASCII XON */ X#define SP 040 /* ASCII Space */ X#define DEL 0177 /* ASCII Delete (Rubout) */ X X/* Kermit parameters and defaults */ X X#define MAXPACK 94 /* Maximum packet size */ X#define RBUFL 200 /* Receive buffer length */ X#define CTLQ '#' /* Control char prefix I will use */ X#define MYEBQ '&' /* 8th-Bit prefix char I will use */ X#define MYRPTQ '~' /* Repeat count prefix I will use */ X X#define MAXTRY 10 /* Times to retry a packet */ X#define MYPADN 0 /* How many padding chars I need */ X#define MYPADC '\0' /* Which padding character I need */ X X#define DMYTIM 7 /* Default timeout interval to use. */ X#define URTIME 10 /* Timeout interval to be used on me. */ X X#define DEFTRN 0 /* Default line turnaround handshake */ X#define DEFPAR 0 /* Default parity */ X#define MYEOL CR /* End-Of-Line character I need on packets. */ X X#define DRPSIZ 90 /* Default incoming packet size. */ X#define DSPSIZ 90 /* Default outbound packet size. */ X X#define DDELAY 5 /* Default delay. */ X#define DSPEED 9600 /* Default line speed. */ X X/* Files */ X X#define ZCTERM 0 /* Console terminal */ X#define ZSTDIO 1 /* Standard input/output */ X#define ZIFILE 2 /* Current input file */ X#define ZOFILE 3 /* Current output file */ X#define ZDFILE 4 /* Current debugging log file */ X#define ZTFILE 5 /* Current transaction log file */ X#define ZPFILE 6 /* Current packet log file */ X#define ZSFILE 7 /* Current session log file */ X#define ZNFILS 8 /* How many defined file numbers */ X X/* Macros */ X X#define tochar(ch) ((ch) + SP ) /* Number to character */ X#define unchar(ch) ((ch) - SP ) /* Character to number */ X#define ctl(ch) ((ch) ^ 64 ) /* Controllify/Uncontrollify */ X#define unpar(ch) ((ch) & 127) /* Clear parity bit */ !FUNKY!STUFF! echo x - ckermi.hlp sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.hlp XThe files ck*.* comprise C-Kermit. X Xck*.c are the C language source files. Xck*.h are the header files. Xckprot.w is the "wart" source for the protocol state table. X Xckermi.mss is the Scribe text formatter source for the Kermit User Guide Xchapter on C-Kermit for Unix. X Xckermi.doc is the plain-text documentation output from Scribe. X Xckermi.mak is the makefile. It should be renamed to "makefile". Use the Xmakefile to build C-Kermit for your Unix system, giving the appropriate Xcommand line argument to "make", e.g. X Xmake bsd (for Berkeley Unix) Xmake pcix (for PC/IX) Xmake provx1 (for Pro-350 with Venix 1.0) X Xetc. The make file produces a runnable program called "wermit". You should Xtest it thoroughly before renaming it to "kermit". !FUNKY!STUFF! echo x - ckermi.mak sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckermi.mak X# Makefile to build C-Kermit for Berkeley, Microsoft, Interactive, X# and ATT Unix X# for Berkeley Unix 4.x, "make bsd" X# for Microsoft xenix (/286, pc/at, etc) "make xenix" X# for Interactive on pc/xt "make pcix" X# for Interactive on other host "make is3" X# for Bell generic III/V "make sys3" X# for Pro-3xx Venix 1.0 "make provx1" X# for NCR Tower 1632, "make tower1" X XLNKFLAGS= X Xmake: X @echo 'Make what? You must tell which system to make C-Kermit for.' X Xwermit: ckmain.o ckcmd.o ckuser.o ckusr2.o ckusr3.o ckprot.o ckfns.o ckfns2.o \ X ckconu.o ckxunx.o ckzunx.o ckdial.o cklogi.o makefile X cc $(LNKFLAGS) -o wermit ckmain.o ckxunx.o ckzunx.o ckfns.o ckfns2.o \ X ckprot.o ckcmd.o ckusr2.o ckusr3.o ckuser.o ckconu.o \ X ckdial.o cklogi.o X Xckmain.o: ckmain.c ckermi.h X Xckuser.o: ckuser.c ckcmd.h ckermi.h ckuser.h X Xckusr2.o: ckusr2.c ckcmd.h ckermi.h ckuser.h X Xckusr3.o: ckusr3.c ckcmd.h ckermi.h ckuser.h X Xckcmd.o: ckcmd.c ckcmd.h ckdebu.h X Xckprot.o: ckprot.w wart ckermi.h X wart ckprot.w ckprot.c ; cc $(CFLAGS) -c ckprot.c X Xckfns.o: ckfns.c ckermi.h ckdebu.h X Xckfns2.o: ckfns.c ckermi.h ckdebu.h X Xckzunx.o: ckzunx.c ckermi.h ckdebu.h X Xckxunx.o: ckxunx.c ckdebu.h X Xckconu.o: ckconu.c ckermi.h X Xwart: ckwart.o X cc $(LNKFLAGS) -o wart ckwart.o X Xckwart.o: ckwart.c X Xckdial.o: ckdial.c X Xcklogi.o: cklogi.c X X#Berkeley Unix Xbsd: X make wermit "CFLAGS= -DBSD4" X X#Microsoft "Xenix/286" e.g., as sold by IBM for PC/AT Xxenix: X make wermit "CFLAGS= -DXENIX -DUXIII -F3000 -i" "LNKFLAGS = -F3000 -i" X X#PC/IX, Interactive Corp System III port for IBM PC/XT as sold by IBM Xpcix: X make wermit "CFLAGS= -DPCIX -DUXIII -DISIII -Dsdata=sdatax -O -i" \ X "LNKFLAGS = -i" X X#interactive corp system III port -- Xis3: X make wermit "CFLAGS = -DISIII -DUXIII -Ddata=datax -O -i" \ X "LNKFLAGS = -i" X X#plain old Bell System III or System V without strange things Xsys3: X make wermit "CFLAGS = -DUXIII -i -O" "LNKFLAGS = -i" X X#DEC Pro-3xx with Venix 1.0 Xprovx1: X make wart "CFLAGS= " "LNKFLAGS= " X make wermit "CFLAGS = -DPROVX1 -md780" \ X "LNKFLAGS= -u _sleep -lc -md780" X X#NCR Tower 1632, OS 1.02 Xtower1: X make wermit "CFLAGS = -DTOWER1" X !FUNKY!STUFF! echo x - ckprot.w sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckprot.w Xchar *protv = "C-Kermit Protocol Module 4.2(015), 5 Mar 85"; /* -*-C-*- */ X X/* C K P R O T -- C-Kermit Protocol Module, in Wart preprocessor notation. */ X X/* Authors: Jeff Damens, Bill Catchings, Frank da Cruz (Columbia University) */ X X#include "ckermi.h" X/* X Note -- This file may also be preprocessed by the Unix Lex program, but X you must indent the above #include statement before using Lex, and then X restore it to the left margin in the resulting C program before compilation. X Also, the invocation of the "wart()" function below must be replaced by an X invocation of the "yylex()" function. It might also be necessary to remove X comments in the %%...%% section. X*/ X X X/* State definitions for Wart (or Lex) */ X X%states ipkt rfile rdata ssinit ssdata sseof sseot serve generic get rgen X X X/* External C-Kermit variable declarations */ X X extern char sstate, *versio, *srvtxt, *cmarg, *cmarg2; X extern char data[], filnam[], srvcmd[], ttname[], *srvptr; X extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp; X extern int prvpkt, cxseen, czseen, server, local, displa, bctu, bctr, quiet; X extern int putsrv(), puttrm(), putfil(), errpkt(); X extern char *DIRCMD, *DELCMD, *TYPCMD, *SPACMD, *SPACM2, *WHOCMD; X X X/* Local variables */ X X static char vstate = 0; /* Saved State */ X static char vcmd = 0; /* Saved Command */ X static int x; /* General-purpose integer */ X X X/* Macros - Note, BEGIN is predefined by Wart (and Lex) */ X X#define SERVE tinit(); BEGIN serve X#define RESUME if (server) { SERVE; } else return X X%% X/* Protocol entry points, one for each start state (sstate) */ X Xs { tinit(); /* Do Send command */ X if (sinit()) BEGIN ssinit; X else RESUME; } X Xv { tinit(); BEGIN get; } /* Receive */ Xr { tinit(); vstate = get; vcmd = 0; sipkt(); BEGIN ipkt; } /* Get */ Xc { tinit(); vstate = rgen; vcmd = 'C'; sipkt(); BEGIN ipkt; } /* Host */ Xg { tinit(); vstate = rgen; vcmd = 'G'; sipkt(); BEGIN ipkt; } /* Generic */ X Xx { SERVE; } /* Be a Server */ X X/* Dynamic states: <current-states>input-character { action } */ X X<rgen,get,serve>S { rinit(data); bctu = bctr; BEGIN rfile; } /* Send-Init */ X X<ipkt>Y { spar(data); /* Get ack for I-packet */ X if (vcmd) { scmd(vcmd,cmarg); vcmd = 0; } X if (vstate == get) srinit(); X BEGIN vstate; } X X<ipkt>E { if (vcmd) scmd(vcmd,cmarg); /* Get E for I-packet (ignore) */ X vcmd = 0; if (vstate == get) srinit(); X BEGIN vstate; } X X<serve>R { srvptr = srvcmd; decode(data,putsrv); /* Get Receive-Init */ X cmarg = srvcmd; nfils = -1; X if (sinit()) BEGIN ssinit; else { SERVE; } } X X<serve>I { spar(data); rpar(data); ack1(data); /* Get Init Parameters */ X pktnum = 0; prvpkt = -1; } X X<serve>G { srvptr = srvcmd; decode(data,putsrv); /* Get & decode command. */ X putsrv('\0'); putsrv('\0'); X sstate = srvcmd[0]; BEGIN generic; } X X<serve>C { srvptr = srvcmd; /* Get command for shell */ X decode(data,putsrv); putsrv('\0'); X if (syscmd("",srvcmd)) BEGIN ssinit; X else { errpkt("Can't do shell command"); SERVE; } } X X<serve>. { errpkt("Unimplemented server function"); SERVE; } /* Other */ X X<generic>C { if (!cwd(srvcmd+1)) errpkt("Can't change directory"); /* CWD */ X SERVE; } X X<generic>D { if (syscmd(DIRCMD,srvcmd+2)) BEGIN ssinit; /* Directory */ X else { errpkt("Can't list directory"); SERVE; } } X X<generic>E { if (syscmd(DELCMD,srvcmd+2)) BEGIN ssinit; /* Erase */ X else { errpkt("Can't remove file"); SERVE; } } X X<generic>F { ack(); return(0); } /* Finish */ X<generic>L { ack(); ttres(); return(kill(0,9)); } /* Bye, but no guarantee! */ X X<generic>H { if (sndhlp()) BEGIN ssinit; X else { errpkt("Can't send help"); SERVE; } } X X<generic>T { if (syscmd(TYPCMD,srvcmd+2)) BEGIN ssinit; X else { errpkt("Can't type file"); SERVE; } } X X<generic>U { x = *(srvcmd+1); /* Disk Usage query */ X x = ((x == '\0') || (x == unchar(0))); X x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,srvcmd+2)); X if (x) BEGIN ssinit; else { errpkt("Can't check space"); SERVE; }} X X<generic>W { if (syscmd(WHOCMD,srvcmd+2)) BEGIN ssinit; X else { errpkt("Can't do who command"); SERVE; } } X X<generic>. { errpkt("Unimplemented generic server function"); SERVE; } X X/* Dynamic states, cont'd */ X X X<rgen>Y { decode(data,puttrm); RESUME; } /* Got reply in ACK data */ X X<rgen,rfile>F { if (rcvfil()) { ack(); BEGIN rdata; } /* A file is coming */ X else { errpkt("Can't open file"); RESUME; } } X X<rgen,rfile>X { opent(); ack(); BEGIN rdata; } /* Screen data is coming */ X X<rfile>B { ack(); reot(); RESUME; } /* Got End Of Transmission */ X X<rdata>D { if (cxseen) ack1("X"); /* Got data. */ X else if (czseen) ack1("Z"); X else ack(); X decode(data,putfil); } X X<rdata>Z { ack(); reof(); BEGIN rfile; } /* Got End Of File */ X X<ssinit,ssdata,sseof,sseot>N { resend(); } /* Got a NAK, resend. */ X X<ssinit>Y { int x; char *s; /* Got ACK to Send-Init */ X spar(data); X bctu = bctr; X if (xflg) { x = sxpack(); s = "Can't execute command"; } X else { x = sfile(); s = "Can't open file"; } X if (x) BEGIN ssdata; else { errpkt(s); RESUME; } X } X X<ssdata>Y { if (canned(data) || !sdata()) { /* Got ACK to data */ X clsif(); seof(); X BEGIN sseof; } } X X<sseof>Y { if (gnfile() > 0) { /* Got ACK to EOF, get next file */ X if (sfile()) BEGIN ssdata; X else { errpkt("Can't open file") ; RESUME; } X } else { /* If no next file, EOT */ X seot(); X BEGIN sseot; } } X X<sseot>Y { RESUME; } /* Got ACK to EOT */ X XE { ermsg(data); /* Error packet, issue message */ X x = quiet; quiet = 1; /* Close files silently */ X clsif(); clsof(); X quiet = x; RESUME; } X X. { nack(); } /* Anything else, send NAK */ X%% X X/* P R O T O -- Protocol entry function */ X Xproto() { X X extern int sigint(); X int x; X X conint(sigint); /* Enable console interrupts */ X X/* Set up the communication line for file transfer. */ X X if (local && (speed < 0)) { X screen(2,0l,"Sorry, you must 'set speed' first"); X return; X } X if (ttopen(ttname,local,mdmtyp) < 0) { X screen(2,0l,"Can't open line"); X return; X } X x = (local) ? speed : -1; X if (ttpkt(x,flow) < 0) { /* Put line in packet mode, */ X screen(2,0l,"Can't condition line"); /* setting speed, flow control */ X return; X } X if (sstate == 'x') { /* If entering server mode, */ X server = 1; /* set flag, */ X if (!quiet) { X if (!local) /* and issue appropriate message. */ X conol(srvtxt); X else { X conol("Entering server mode on "); X conoll(ttname); X } X } X } else server = 0; X sleep(1); X X/* X The 'wart()' function is generated by the wart program. It gets a X character from the input() routine and then based on that character and X the current state, selects the appropriate action, according to the state X table above, which is transformed by the wart program into a big case X statement. The function is active for one transaction. X*/ X X wart(); /* Enter the state table switcher. */ X X if (server) { /* Back from packet protocol. */ X server = 0; X if (!quiet) /* Give appropriate message */ X conoll("C-Kermit server done"); X } else X screen(BEL,0l,""); /* Or beep */ X} !FUNKY!STUFF! echo x - ckuser.h sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckuser.h X/* C K U S E R . H -- Symbol definitions for C-Kermit ckus*.c modules */ X X X/* Values associated with top-level commands, must be 0 or greater. */ X X#define XXBYE 0 /* BYE */ X#define XXCLE 1 /* CLEAR */ X#define XXCLO 2 /* CLOSE */ X#define XXCON 3 /* CONNECT */ X#define XXCPY 4 /* COPY */ X#define XXCWD 5 /* CWD (Change Working Directory) */ X#define XXDEF 6 /* DEFINE (a command macro) */ X#define XXDEL 7 /* (Local) DELETE */ X#define XXDIR 8 /* (Local) DIRECTORY */ X#define XXDIS 9 /* DISCONNECT */ X#define XXECH 10 /* ECHO */ X#define XXEXI 11 /* EXIT */ X#define XXFIN 12 /* FINISH */ X#define XXGET 13 /* GET */ X#define XXHLP 14 /* HELP */ X#define XXINP 15 /* INPUT */ X#define XXLOC 16 /* LOCAL */ X#define XXLOG 17 /* LOG */ X#define XXMAI 18 /* MAIL */ X#define XXMOU 19 /* (Local) MOUNT */ X#define XXMSG 20 /* (Local) MESSAGE */ X#define XXOUT 21 /* OUTPUT */ X#define XXPAU 22 /* PAUSE */ X#define XXPRI 23 /* (Local) PRINT */ X#define XXQUI 24 /* QUIT */ X#define XXREC 25 /* RECEIVE */ X#define XXREM 26 /* REMOTE */ X#define XXREN 27 /* (Local) RENAME */ X#define XXSEN 28 /* SEND */ X#define XXSER 29 /* SERVER */ X#define XXSET 30 /* SET */ X#define XXSHE 31 /* Command for SHELL */ X#define XXSHO 32 /* SHOW */ X#define XXSPA 33 /* (Local) SPACE */ X#define XXSTA 34 /* STATISTICS */ X#define XXSUB 35 /* (Local) SUBMIT */ X#define XXTAK 36 /* TAKE */ X#define XXTRA 37 /* TRANSMIT */ X#define XXTYP 38 /* (Local) TYPE */ X#define XXWHO 39 /* (Local) WHO */ X#define XXDIAL 40 /* (Local) dial */ X#define XXLOGI 41 /* (Local) logon */ X X/* SET parameters */ X X#define XYBREA 0 /* BREAK simulation */ X#define XYCHKT 1 /* Block check type */ X#define XYDEBU 2 /* Debugging */ X#define XYDELA 3 /* Delay */ X#define XYDUPL 4 /* Duplex */ X#define XYEOL 5 /* End-Of-Line (packet terminator) */ X#define XYESC 6 /* Escape character */ X#define XYFILE 7 /* File Parameters */ X#define XYFILN 0 /* Naming */ X#define XYFILT 1 /* Type */ X#define XYFILW 2 /* Warning */ X#define XYFILD 3 /* ... */ X/* empty space to add something */ X#define XYFLOW 9 /* Flow Control */ X#define XYHAND 10 /* Handshake */ X#define XYIFD 11 /* Incomplete File Disposition */ X#define XYIMAG 12 /* "Image Mode" */ X#define XYINPU 13 /* INPUT command parameters */ X#define XYLEN 14 /* Maximum packet length to send */ X#define XYLINE 15 /* Communication line to use */ X#define XYLOG 16 /* Log file */ X#define XYMARK 17 /* Start of Packet mark */ X#define XYNPAD 18 /* Amount of padding */ X#define XYPADC 19 /* Pad character */ X#define XYPARI 20 /* Parity */ X#define XYPAUS 21 /* Interpacket pause */ X#define XYPROM 22 /* Program prompt string */ X#define XYQBIN 23 /* 8th-bit prefix */ X#define XYQCTL 24 /* Control character prefix */ X#define XYREPT 25 /* Repeat count prefix */ X#define XYRETR 26 /* Retry limit */ X#define XYSPEE 27 /* Line speed (baud rate) */ X#define XYTACH 28 /* Character to be doubled */ X#define XYTIMO 29 /* Timeout interval */ X#define XYMODM 30 /* Modem type */ X X/* REMOTE command symbols */ X X#define XZCPY 0 /* Copy */ X#define XZCWD 1 /* Change Working Directory */ X#define XZDEL 2 /* Delete */ X#define XZDIR 3 /* Directory */ X#define XZHLP 4 /* Help */ X#define XZHOS 5 /* Host */ X#define XZKER 6 /* Kermit */ X#define XZLGI 7 /* Login */ X#define XZLGO 8 /* Logout */ X#define XZMAI 9 /* Mail */ X#define XZMOU 10 /* Mount */ X#define XZMSG 11 /* Message */ X#define XZPRI 12 /* Print */ X#define XZREN 13 /* Rename */ X#define XZSET 14 /* Set */ X#define XZSPA 15 /* Space */ X#define XZSUB 16 /* Submit */ X#define XZTYP 17 /* Type */ X#define XZWHO 18 /* Who */ X X/* Symbols for logs */ X X#define LOGD 0 /* Debugging */ X#define LOGP 1 /* Packets */ X#define LOGS 2 /* Session */ X#define LOGT 3 /* Transaction */ !FUNKY!STUFF! echo x - ckwart.doc sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckwart.doc XWART X XWart is a program that implements a small subset of the Unix 'lex' Xlexical analyzer generator. Unlike lex, wart may be distributed without Xrequirement for a Unix license. Wart was written at the Columbia University XCenter of Computing Activities to facilitate development of Unix Kermit. X XWart is intended for production of state table switchers. It allows a Xset of states to be defined, along with a function for getting input. The Xperforms actions and switches states based on the current state and the Xinput. X XThe following short program demonstrates some of the capabilities and Xlimitations of Wart. The program accepts from the command line a binary Xnumber, preceded by an optional minus sign, and optionally containing a Xfractional part. It prints the decimal equivalent. X X#include <stdio.h> X Xint state, s = 1, m = 0, d; Xfloat f; Xchar *b; X X%states sign mantissa fraction /* Declare wart states */ X X%% /* Begin state table */ X<sign>- { s = -1; BEGIN mantissa; } /* Look for sign */ X<sign>0 { m = 0; BEGIN mantissa; } /* Got digit, start mantissa */ X<sign>1 { m = 1; BEGIN mantissa; } X<sign>. { fatal("bad input"); } /* Detect bad format */ X<mantissa>0 { m *= 2; } /* Accumulate mantissa */ X<mantissa>1 { m = 2 * m + 1; } X<mantissa>$ { printf("%d\n", s * m); return; } X<mantissa>. { f = 0.0; d = 1; BEGIN fraction; } /* Start fraction */ X<fraction>0 { d *= 2; } /* Accumulate fraction */ X<fraction>1 { d *= 2; f += 1.0 / d; } X<fraction>$ { printf("%f\n", s * (m + f) ); return; } X<fraction>. { fatal("bad input"); } X%% X Xinput() { /* Define input() function */ X int x; X return(((x = *b++) == '\0') ? '$' : x ); X} X Xfatal(s) char *s; { /* Error exit */ X fprintf(stderr,"fatal - %s\n",s); X exit(1); X} X Xmain(argc,argv) int argc; char **argv; { /* Main program */ X if (argc < 1) exit(1); X b = *++argv; X state = sign; /* Initialize state */ X wart(); /* Invoke state switcher */ X exit(0); /* Done */ X} X XThe wart program accepts as input a C program containing lines that start Xwith "%" or sections delimited by "%%". The directive "%states" declares Xthe program's states. The section enclosed by "%%" markers is the state Xtable, with entries of the form X X <state>X { action } X Xwhich read as "if in state <state> with input X perform { action }" X XThe optional <state> field tells the current state or state the program must Xbe in to perform the indicated action. If no state is specified, then it Xmeans the action will be performed regardless of the current state. If more Xthan one state is specifed, then the action will be performed in any of the Xlisted states. Multiple states are separated by commas. X XThe required input field consists of a single literal character. When in Xthe indicated state, if the input is the specified character, then the Xassociated action will be performed. The character '.' matches any input Xcharacter. No pattern matching or range notation is provided. The input Xcharacter is obtained from the input() function, which you must define. It Xshould be alphanumeric, or else one of the characters ".% -$@" (quotes not Xincluded). Note that the program above recognize the binary point '.' Xthrough a ruse. X XThe action is a series of zero or more C language statements, enclosed in Xcurly braces. X XThe BEGIN macro is defined simply to be "state = ", as in lex. X XThe wart() function is generated by the wart program based on the state Xdeclarations and the state transition table. It loops through calls to Xinput(), using the result to index into a big case statement it has created Xfrom the state table. X XWart is invoked as follows: X X wart X XInput from stdin, output to stdout X X wart fn1 X XInput from fn1, output to stdout X X wart fn1 fn2 X XInput from fn1, output to fn2. Example: wart a.w a.c X XWart programs have the conventional filetype '.w'. !FUNKY!STUFF! echo x - ckwho.txt sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckwho.txt X(18 Feb 85) X XThe following people have tentatively volunteered to supply support in XC-Kermit 4.0 for the following systems: X X XWhat Who X XDEC Pro-350/380, Venix SY.FDC@CU20B (Frank da Cruz) X XIBM 370-series, Ahmdah UTS SY.FDC@CU20B (Frank da Cruz) X XApple Macintosh SY.WBC3@CU20B (Bill Catchings) X XMasscomp RTU 2.2 sob@RICE (Stan Barber) X XCoherent vortex!lauren@RAND-UNIX (Lauren Weinstein) X XCallan UniStar 300 with X Unisoft 68000 System V Unix EBM@MIT-XX (Eliot Moss) X XATT 3Bx, System V Chris@COLUMBIA-20 (Chris Maio) X XIBM PC, etc, PC/IX HFISCHER@USC-ECLB (Herm Fischer) X XIBM PC, etc, Xenix HFISCHER@USC-ECLB (Herm Fischer) X XVAX,PDP-11 with IS3, Interactive X Systems version of System III HFISCHER@USC-ECLB (Herm Fischer) X XOs9 BLARSON@USC-ECL (Bob Larson) X XVersion 7 vasoll%okstate.csnet@CSNET-RELAY (Mark Vasoll) X X4.2 UUCP Line Locking hipl!tony@NYU-CMCL2 (Tony Movshon) X XHP9000 Series 200 (HP9836) X with HP-UX System III b-davis@utah-cs (Brad Davis) X XCP/M (Small C or BDS C) bdale@cmu-cs-g (Bdale Garbee) X XHoneywell GCOS3/8 Carlin%HIS-PHOENIX-MULTICS@MIT-MULTICS X X68000 Xenix ED@MIT-MC (Ed Schwalenberg) X XVAX, 2.0 BSD nsc!jon@DECWRL (Jon Ryshpan) X XCP/M-86, De Smet C nsc!jon@DECWRL (Jon Ryshpan) X XLogin scripts, raw upload poulton%hplabs.csnet@CSNET-RELAY (Ken Poulton) X XApple II, Aztec C Saline@MIT-MULTICS (Steven Saline) !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckfns.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckfns.c Xchar *fnsv = "C-Kermit functions, 4.2(026) 5 Mar 85"; X X/* C K F N S -- System-independent Kermit protocol support functions... */ X X/* ...Part 1 (others moved to ckfns2 to make this module small enough) */ X X/* X System-dependent primitives defined in: X X ckx???.c -- terminal i/o X cxz???.c -- file i/o, directory structure X X*/ X X#include "ckermi.h" /* Symbol definitions for Kermit */ X X/* Externals from ckmain.c */ X Xextern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; X Xextern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu, X size, osize, maxsize, spktl, nfils, stdouf, warn, timef; X Xextern int parity, speed, turn, turnch, X delay, displa, pktlog, tralog, seslog, xflg, mypadn; X Xextern long filcnt, ffc, flci, flco, tlci, tlco, tfc; X Xextern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; X Xextern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt; X Xextern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, X mystch; X Xextern char *cmarg, *cmarg2, **cmlist; Xchar *strcpy(); X X/* Variables local to this module */ X Xstatic char *memptr; /* Pointer for memory strings */ X Xstatic char cmdstr[100]; /* Unix system command string */ X Xstatic int sndsrc; /* Flag for where to send from: */ X /* -1: name in cmdata */ X /* 0: stdin */ X /* >0: list in cmlist */ X Xstatic int memstr, /* Flag for input from memory string */ X t, /* Current character */ X next; /* Next character */ X X/* E N C S T R -- Encode a string from memory. */ X X/* Call this instead of getpkt() if source is a string, rather than a file. */ X Xencstr(s) char* s; { X int m; char *p; X X m = memstr; p = memptr; /* Save these. */ X X memptr = s; /* Point to the string. */ X memstr = 1; /* Flag memory string as source. */ X next = -1; /* Initialize character lookahead. */ X getpkt(spsiz); /* Fill a packet from the string. */ X memstr = m; /* Restore memory string flag */ X memptr = p; /* and pointer */ X next = -1; /* Put this back as we found it. */ X debug(F111,"encstr",data,size); X} X X/* E N C O D E - Kermit packet encoding procedure */ X Xencode(a) int a; { /* The current character */ X int a7; /* Low order 7 bits of character */ X int b8; /* 8th bit of character */ X X if (rptflg) { /* Repeat processing? */ X if (a == next) { /* Got a run... */ X if (++rpt < 94) /* Below max, just count */ X return; X else if (rpt == 94) { /* Reached max, must dump */ X data[size++] = rptq; X data[size++] = tochar(rpt); X rpt = 0; X } X } else if (rpt == 1) { /* Run broken, only 2? */ X rpt = 0; /* Yes, reset repeat flag & count. */ X encode(a); /* Do the character twice. */ X if (size <= maxsize) osize = size; X rpt = 0; X encode(a); X return; X } else if (rpt > 1) { /* More than two */ X data[size++] = rptq; /* Insert the repeat prefix */ X data[size++] = tochar(++rpt); /* and count. */ X rpt = 0; /* Reset repeat counter. */ X } X } X a7 = a & 0177; /* Isolate ASCII part */ X b8 = a & 0200; /* and 8th (parity) bit. */ X X if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ X data[size++] = ebq; X a = a7; X } X if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ X data[size++] = myctlq; X a = ctl(a); X } X if (a7 == myctlq) /* Prefix the control prefix */ X data[size++] = myctlq; X X if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ X data[size++] = myctlq; /* quote it if doing repeat counts. */ X X if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ X data[size++] = myctlq; /* if doing 8th-bit prefixes */ X X data[size++] = a; /* Finally, insert the character */ X data[size] = '\0'; /* itself, and mark the end. */ X} X X/* D E C O D E -- Kermit packet decoding procedure */ X X/* Call with string to be decoded and an output function. */ X Xdecode(buf,fn) char *buf; int (*fn)(); { X unsigned int a, a7, b8; /* Low order 7 bits, and the 8th bit */ X X rpt = 0; X X while ((a = *buf++) != '\0') { X if (rptflg) { /* Repeat processing? */ X if (a == rptq) { /* Yes, got a repeat prefix? */ X rpt = unchar(*buf++); /* Yes, get the repeat count, */ X a = *buf++; /* and get the prefixed character. */ X } X } X b8 = 0; /* Check high order "8th" bit */ X if (ebqflg) { /* 8th-bit prefixing? */ X if (a == ebq) { /* Yes, got an 8th-bit prefix? */ X b8 = 0200; /* Yes, remember this, */ X a = *buf++; /* and get the prefixed character. */ X } X } X if (a == ctlq) { /* If control prefix, */ X a = *buf++; /* get its operand. */ X a7 = a & 0177; /* Only look at low 7 bits. */ X if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */ X a = ctl(a); /* if in control range. */ X } X a |= b8; /* OR in the 8th bit */ X if (rpt == 0) rpt = 1; /* If no repeats, then one */ X for (; rpt > 0; rpt--) { /* Output the char RPT times */ X if (a == CR && !binary) break; /* But skip CR if binary. */ X ffc++, tfc++; /* Count the character */ X (*fn)(a); /* Send it to the output function. */ X } X } X} X X X/* Output functions passed to 'decode': */ X Xputsrv(c) char c; { /* Put character in server command buffer */ X *srvptr++ = c; X *srvptr = '\0'; /* Make sure buffer is null-terminated */ X} X Xputtrm(c) char c; { /* Output character to console. */ X conoc(c); X} X Xputfil(c) char c; { /* Output char to file. */ X zchout(ZOFILE,c); X} X X/* G E T P K T -- Fill a packet data field */ X X/* X Gets characters from the current source -- file or memory string. X Encodes the data into the packet, filling the packet optimally. X X Uses global variables: X t -- current character. X next -- next character. X data -- the packet data buffer. X size -- number of characters in the data buffer. X XReturns the size as value of the function, and also sets global size, Xand fills (and null-terminates) the global data array. X XBefore calling getpkt the first time for a given source (file or string), Xset the variable 'next' to -1. X*/ X Xgetpkt(maxsize) int maxsize; { /* Fill one packet buffer */ X int i; /* Loop index. */ X X static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' }; X X if (next < 0) t = getch(); /* Get first character of file. */ X X /* Do any leftovers */ X X for (size = 0; (data[size] = leftover[size]) != '\0'; size++) X ; X *leftover = '\0'; X X /* Now fill up the rest of the packet. */ X X while(t >= 0) { /* Until EOF... */ X next = getch(); /* Get next character for lookahead. */ X osize = size; /* Remember current position. */ X encode(t); /* Encode the current character. */ X t = next; /* Next is now current. */ X X if (size == maxsize) /* If the packet is exactly full, */ X return(size); /* and return. */ X X if (size > maxsize) { /* If too big, save some for next. */ X for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++) X ; X size = osize; /* Return truncated packet. */ X data[size] = '\0'; X return(size); X } X } X return(size); /* Return any partial final buffer. */ X} X X/* G E T C H -- Get the next character from file (or pipe). */ X X/* Convert newlines to CRLFs if newline/CRLF mapping is being done. */ X Xgetch() { /* Get next character */ X int a, x; /* The character to return. */ X static int b = 0; /* A character to remember. */ X X if (b > 0) { /* Do we have a newline saved? */ X b = 0; /* Yes, return that. */ X return('\n'); X } X X if (memstr) /* Try to get the next character */ X x = ((a = *memptr++) == '\0'); /* from the appropriate source, */ X else /* memory or the current file. */ X x = ((a = zchin(ZIFILE)) < 0 ); X X if (x) X return(-1); /* No more, return -1 for EOF. */ X else { /* Otherwise, read the next char. */ X ffc++, tfc++; /* Count it. */ X if (a == '\n' && !binary) { /* If nl and we must do nl-CRLF */ X b = a; /* mapping, save the nl, */ X return(CR); /* and return a CR. */ X } else return(a); /* General case, return the char. */ X } X} X X X/* C A N N E D -- Check if current file transfer cancelled */ X Xcanned(buf) char *buf; { X if (*buf == 'X') cxseen = 1; X if (*buf == 'Z') czseen = 1; X debug(F101,"canned: cxseen","",cxseen); X debug(F101," czseen","",czseen); X return((czseen || cxseen) ? 1 : 0); X} X X/* T I N I T -- Initialize a transaction */ X Xtinit() { X xflg = 0; /* reset x-packet flag */ X memstr = 0; /* reset memory-string flag */ X memptr = NULL; /* and pointer */ X bctu = 1; /* reset block check type to 1 */ X filcnt = 0; /* reset file counter */ X tfc = tlci = tlco = 0; /* reset character counters */ X prvpkt = -1; /* reset packet number */ X pktnum = 0; X if (server) { /* If acting as server, */ X timint = 30; /* use 30 second timeout, */ X nack(); /* send a NAK */ X } X} X X X/* R I N I T -- Respond to S packet */ X Xrinit(d) char *d; { X char *tp; X ztime(&tp); X tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ X tfc = tlci = tlco = 0; X spar(d); X rpar(d); X ack1(d); X} X X/* S I N I T -- Make sure file exists, then send Send-Init packet */ X Xsinit() { X int x; char *tp; X X sndsrc = nfils; /* Where to look for files to send */ X ztime(&tp); X tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ X debug(F101,"sinit: sndsrc","",sndsrc); X if (sndsrc < 0) { /* Must expand from 'send' command */ X nfils = zxpand(cmarg); /* Look up literal name. */ X if (nfils < 0) { X screen(2,0l,"?Too many files"); X return(0); X } else if (nfils == 0) { /* If none found, */ X char xname[100]; /* convert the name. */ X zrtol(cmarg,xname); X nfils = zxpand(xname); /* Look it up again. */ X } X if (nfils < 1) { /* If no match, report error. */ X if (server) X errpkt("File not found"); X else X screen(2,0l,"?File not found"); X return(0); X } X x = gnfile(); /* Position to first file. */ X if (x < 1) { X if (!server) X screen(2,0l,"?No readable file to send"); X else X errpkt("No readable file to send"); X return(0); X } X } else if (sndsrc > 0) { /* Command line arglist -- */ X x = gnfile(); /* Get the first file from it. */ X if (x < 1) return(0); /* (if any) */ X } else if (sndsrc == 0) { /* stdin or memory always exist... */ X cmarg2 = ""; /* No alternate name */ X strcpy(filnam,"stdin"); /* If F packet, filnam is used. */ X tlog(F110,"Sending from",cmdstr,0l); /* If X packet, cmdstr is used. */ X } X X debug(F101,"sinit: nfils","",nfils); X debug(F110," filnam",filnam,0); X debug(F110," cmdstr",cmdstr,0); X ttflui(); /* Flush input buffer. */ X x = rpar(data); /* Send a Send-Init packet. */ X if (!local && !server) sleep(delay); X spack('S',pktnum,x,data); X return(1); X} X Xsipkt() { X int x; X x = rpar(data); /* Send an I-Packet. */ X spack('I',pktnum,x,data); X} X X/* R C V F I L -- Receive a file */ X Xrcvfil() { X int x; X ffc = flci = flco = 0; /* Init per-file counters */ X srvptr = srvcmd; /* Decode packet data. */ X decode(data,putsrv); X screen(0,0l,srvcmd); /* Update screen */ X screen(1,0l,"=> "); X tlog(F110,"Receiving",srvcmd,0l); /* Transaction log entry */ X if (cmarg2 != NULL) { /* Check for alternate name */ X if (*cmarg2 != '\0') { X strcpy(srvcmd,cmarg2); /* Got one, use it. */ X *cmarg2 = '\0'; X } X } X x = openo(srvcmd,filnam); /* Try to open it */ X if (x) { X tlog(F110," as",filnam,0l); X screen(2,0l,filnam); X intmsg(++filcnt); X } else { X tlog(F110,"Failure to open",filnam,0l); X screen(2,0l,"*** error"); X } X return(x); /* Pass on return code from openo */ X} X X/* R E O F -- Receive End Of File */ X Xreof() { X X if (cxseen == 0) cxseen = (*data == 'D'); X clsof(); X if (cxseen || czseen) { X tlog(F100," *** Discarding","",0l); X } else { X tlog(F100," end of file","",0l); X tlog(F101," file characters ","",ffc); X tlog(F101," communication line in ","",flci); X tlog(F101," communication line out ","",flco); X } X} X X/* R E O T -- Receive End Of Transaction */ X Xreot() { X char *tp; X cxseen = czseen = 0; X ztime(&tp); X tlog(F110,"End of transaction",tp,0l); X if (filcnt > 1) { X tlog(F101," files","",filcnt); X tlog(F101," total file characters ","",tfc); X tlog(F101," communication line in ","",tlci); X tlog(F101," communication line out ","",tlco); X } X} X X/* S F I L E -- Send File header packet for global "filnam" */ X Xsfile() { X char pktnam[100]; /* Local copy of name */ X X if (fncnv) { X if (*cmarg2 != '\0') { /* If we have a send-as name, */ X zltor(cmarg2,pktnam); /* convert it to common form, */ X cmarg2 = ""; /* and blank it out for next time, */ X } else zltor(filnam,pktnam); /* otherwise use the real file name. */ X } else { X if (*cmarg2 != '\0') /* Same as above, but without */ X strcpy(pktnam,cmarg2); /* name conversion */ X else strcpy(filnam,pktnam); X } X X debug(F110,"sfile",filnam,0); X if (openi(filnam) == 0) /* Try to open the file */ X return(0); X X rpt = flci = flco = ffc = 0; /* OK, Init counters, etc. */ X encstr(pktnam); /* Encode the name. */ X nxtpkt(&pktnum); /* Increment the packet number */ X ttflui(); /* Clear pending input */ X spack('F',pktnum,size,data); /* Send the F packet */ X if (displa) { X screen(0,(long)pktnum,filnam); /* Update screen */ X screen(1,0l,"=> "); X screen(1,0l,pktnam); X screen(3,(long)fsize,", size"); X intmsg(++filcnt); /* Count file, give interrupt msg */ X } X tlog(F110,"Sending",filnam,0l); /* Transaction log entry */ X tlog(F110," as",pktnam,0l); X next = -1; /* Init file character lookahead. */ X return(1); X} X X X/* Send an X Packet -- Like SFILE, but with Text rather than File header */ X Xsxpack() { /* Send an X packet */ X debug(F110,"sxpack",cmdstr,0); X encstr(cmdstr); /* Encode any data. */ X rpt = flci = flco = ffc = 0; /* Init counters, etc. */ X next = -1; /* Init file character lookahead. */ X nxtpkt(&pktnum); /* Increment the packet number */ X spack('X',pktnum,size,data); /* No incrementing pktnum */ X screen(0,(long)pktnum,cmdstr); /* Update screen. */ X intmsg(++filcnt); X tlog(F110,"Sending from:",cmdstr,0l); X return(1); X} X X/* S D A T A -- Send a data packet */ X Xsdata() { X int len; X if (cxseen || czseen) return(0); /* If interrupted, done. */ X if ((len = getpkt(spsiz-chklen-3)) == 0) return(0); /* If no data, done. */ X nxtpkt(&pktnum); /* Increment the packet number */ X spack('D',pktnum,len,data); /* Send the packet */ X return(1); X} X X X/* S E O F -- Send an End-Of-File packet */ X Xseof() { X nxtpkt(&pktnum); /* Increment the packet number */ X if (czseen || cxseen) { X spack('Z',pktnum,1,"D"); X tlog(F100," *** interrupted, sending discard request","",0l); X } else { X spack('Z',pktnum,0,""); X tlog(F100," end of file","",0l); X tlog(F101," file characters ","",ffc); X tlog(F101," communication line in ","",flci); X tlog(F101," communication line out ","",flco); X } X} X X X/* S E O T -- Send an End-Of-Transaction packet */ X Xseot() { X char *tp; X nxtpkt(&pktnum); /* Increment the packet number */ X spack('B',pktnum,0,""); X cxseen = czseen = 0; X ztime(&tp); X tlog(F110,"End of transaction",tp,0l); X if (filcnt > 1) { X tlog(F101," files","",filcnt); X tlog(F101," total file characters ","",tfc); X tlog(F101," communication line in ","",tlci); X tlog(F101," communication line out ","",tlco); X } X} X X/* R P A R -- Fill the data array with my send-init parameters */ X Xrpar(data) char data[]; { X data[0] = tochar(spsiz); /* Biggest packet I can receive */ X data[1] = tochar(URTIME); /* When I want to be timed out */ X data[2] = tochar(mypadn); /* How much padding I need (none) */ X data[3] = ctl(mypadc); /* Padding character I want */ X data[4] = tochar(MYEOL); /* End-Of-Line character I want */ X data[5] = CTLQ; /* Control-Quote character I send */ X if (ebqflg) data[6] = ebq = '&'; X else data[6] = 'Y'; /* 8-bit quoting */ X data[7] = bctr + '0'; /* Block check type */ X data[8] = MYRPTQ; /* Do repeat counts */ X data[9] = '\0'; X return(9); /* Return the length. */ X} X X/* S P A R -- Get the other system's Send-Init parameters. */ X Xspar(data) char data[]; { X int len, x; X X len = strlen(data); /* Number of fields */ X X spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ; /* Packet size */ X if (spsiz < 10) spsiz = DSPSIZ; X X x = (len-- > 0) ? unchar(data[1]) : DMYTIM; /* Timeout */ X if (!timef) { /* Only use if not overridden */ X timint = x; X if (timint < 0) timint = DMYTIM; X } X X npad = 0; padch = '\0'; /* Padding */ X if (len-- > 0) { X npad = unchar(data[2]); X if (len-- > 0) padch = ctl(data[3]); else padch = 0; X } X X eol = (len-- > 0) ? unchar(data[4]) : '\r'; /* Terminator */ X if ((eol < 2) || (eol > 037)) eol = '\r'; X X ctlq = (len-- > 0) ? data[5] : CTLQ; /* Control prefix */ X X if (len-- > 0) { /* 8th-bit prefix */ X ebq = data[6]; X if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) { X ebqflg = 1; X } else if (parity && (ebq == 'Y')) { X ebqflg = 1; X ebq = '&'; X } else if (ebq == 'N') { X ebqflg = 0; X } else ebqflg = 0; X } else ebqflg = 0; X X chklen = 1; /* Block check */ X if (len-- > 0) { X chklen = data[7] - '0'; X if ((chklen < 1) || (chklen > 3)) chklen = 1; X } X bctr = chklen; X X if (len-- > 0) { /* Repeat prefix */ X rptq = data[8]; X rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177)); X } else rptflg = 0; X X if (deblog) sdebu(len); X} X X/* S D E B U -- Record spar results in debugging log */ X Xsdebu(len) int len; { X debug(F111,"spar: data",data,len); X debug(F101," spsiz ","",spsiz); X debug(F101," timint","",timint); X debug(F101," npad ","",npad); X debug(F101," padch ","",padch); X debug(F101," eol ","",eol); X debug(F101," ctlq ","",ctlq); X debug(F101," ebq ","",ebq); X debug(F101," ebqflg","",ebqflg); X debug(F101," chklen","",chklen); X debug(F101," rptq ","",rptq); X debug(F101," rptflg","",rptflg); X} X X/* G N F I L E -- Get the next file name from a file group. */ X X/* Returns 1 if there's a next file, 0 otherwise */ X Xgnfile() { X int x, y; X X/* If file group interruption (C-Z) occured, fail. */ X X debug(F101,"gnfile: czseen","",czseen); X X if (czseen) { X tlog(F100,"Transaction cancelled","",0l); X return(0); X } X X/* If input was stdin or memory string, there is no next file. */ X X if (sndsrc == 0) return(0); X X/* If file list comes from command line args, get the next list element. */ X X y = -1; X while (y < 0) { /* Keep trying till we get one... */ X X if (sndsrc > 0) { X if (nfils-- > 0) { X strcpy(filnam,*cmlist++); X debug(F111,"gnfile: cmlist filnam",filnam,nfils); X } else { X *filnam = '\0'; X debug(F101,"gnfile cmlist: nfils","",nfils); X return(0); X } X } X X/* Otherwise, step to next element of internal wildcard expansion list. */ X X if (sndsrc < 0) { X x = znext(filnam); X debug(F111,"gnfile znext: filnam",filnam,x); X if (x == 0) return(0); X } X X/* Get here with a filename. */ X X y = zchki(filnam); /* Check if file readable */ X if (y < 0) { X debug(F110,"gnfile skipping:",filnam,0); X tlog(F111,filnam,"not sent, reason",(long)y); X screen(0,0l,"Skipping"); X screen(2,0l,filnam); X } else fsize = y; X } X return(1); X} X X/* O P E N I -- Open an existing file for input */ X Xopeni(name) char *name; { X int x, filno; X if (memstr) return(1); /* Just return if file is memory. */ X X debug(F110,"openi",name,0); X debug(F101," sndsrc","",sndsrc); X X filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */ X X debug(F101," file number","",filno); X X if (zopeni(filno,name)) { /* Otherwise, try to open it. */ X debug(F110," ok",name,0); X return(1); X } else { /* If not found, */ X char xname[100]; /* convert the name */ X zrtol(name,xname); /* to local form and then */ X debug(F110," zrtol:",xname,0); X x = zopeni(filno,xname); /* try opening it again. */ X debug(F101," zopeni","",x); X if (x) { X debug(F110," ok",xname,0); X return(1); /* It worked. */ X } else { X screen(2,0l,"Can't open file"); /* It didn't work. */ X tlog(F110,xname,"could not be opened",0l); X debug(F110," openi failed",xname,0); X return(0); X } X } X} X X/* O P E N O -- Open a new file for output. */ X X/* Returns actual name under which the file was opened in string 'name2'. */ X Xopeno(name,name2) char *name, *name2; { X char xname[100], *xp; X X if (stdouf) /* Receiving to stdout? */ X return(zopeno(ZSTDIO,"")); X X debug(F110,"openo: name",name,0); X X xp = xname; X if (fncnv) /* If desired, */ X zrtol(name,xp); /* convert name to local form */ X else /* otherwise, */ X strcpy(xname,name); /* use it literally */ X X debug(F110,"openo: xname",xname,0); X X if (warn) { /* File collision avoidance? */ X if (zchki(xname) != -1) { /* Yes, file exists? */ X znewn(xname,&xp); /* Yes, make new name. */ X strcpy(xname,xp); X debug(F110," exists, new name ",xname,0); X } X } X if (zopeno(ZOFILE,xname) == 0) { /* Try to open the file */ X debug(F110,"openo failed",xname,0); X tlog(F110,"Failure to open",xname,0l); X return(0); X } else { X strcpy(name2,xname); X debug(F110,"openo ok, name2",name2,0); X return(1); X } X} X X/* O P E N T -- Open the terminal for output, in place of a file */ X Xopent() { X ffc = tfc = 0; X return(zopeno(ZCTERM,"")); X} X X/* C L S I F -- Close the current input file. */ X Xclsif() { X if (memstr) { /* If input was memory string, */ X memstr = 0; /* indicate no more. */ X } else if (hcflg) { X zclosf(); /* If host cmd close fork, */ X } else zclose(ZIFILE); /* else close input file. */ X X screen(1,0l," [OK]"); X hcflg = cxseen = 0; /* Reset flags. */ X} X X X/* C L S O F -- Close an output file. */ X Xclsof() { X zclose(ZOFILE); /* Close it. */ X if (czseen || cxseen) { X zdelet(filnam); /* Delete it if interrupted. */ X debug(F100,"Discarded","",0); X tlog(F100,"Discarded","",0l); X screen(1,0l," [Discarded]"); X } else { X debug(F100,"Closed","",0); X screen(1,0l," [OK]"); X } X cxseen = 0; X} X X/* S N D H L P -- Routine to send builtin help */ X Xsndhlp() { X nfils = 0; /* No files, no lists. */ X xflg = 1; /* Flag we must send X packet. */ X strcpy(cmdstr,"help text"); /* Data for X packet. */ X next = -1; /* Init getch lookahead */ X memstr = 1; /* Just set the flag. */ X memptr = hlptxt; /* And the pointer. */ X return(sinit()); X} X X X/* C W D -- Change current working directory */ X X/* X String passed has first byte as length of directory name, rest of string X is name. Fails if can't connect, else ACKs (with name) and succeeds. X*/ X Xcwd(vdir) char *vdir; { X vdir[unchar(*vdir) + 1] = '\0'; /* End with a null */ X if (zchdir(vdir+1)) { X encstr(vdir+1); X ack1(data); X tlog(F110,"Changed directory to",vdir+1,0l); X return(1); X } else { X tlog(F110,"Failed to change directory to",vdir+1,0l); X return(0); X } X} X X X/* S Y S C M D -- Do a system command */ X X/* Command string is formed by concatenating the two arguments. */ X Xsyscmd(prefix,suffix) char *prefix, *suffix; { X char *cp; X X for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; X while (*cp++ = *suffix++) ; X X debug(F110,"syscmd",cmdstr,0); X if (zxcmd(cmdstr) > 0) { X debug(F100,"zxcmd ok","",0); X nfils = sndsrc = 0; /* Flag that input from stdin */ X xflg = hcflg = 1; /* And special flags for pipe */ X return (sinit()); /* Send S packet */ X } else { X debug(F100,"zxcmd failed","",0); X return(0); X } X} !FUNKY!STUFF! echo x - ckfns2.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckfns2.c X/* C K F N S 2 -- System-independent Kermit protocol support functions... */ X X/* ...Part 2 (continued from ckfns.c) */ X/* X Note -- if you change this file, please amend the version number and date at X the top of ckfns.c accordingly. X*/ X X#include "ckermi.h" X Xextern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; X Xextern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu, X size, osize, maxsize, spktl, nfils, stdouf, warn, timef; X Xextern int parity, speed, turn, turnch, X delay, displa, pktlog, tralog, seslog, xflg, mypadn; X Xextern long filcnt, ffc, flci, flco, tlci, tlco, tfc; X Xextern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; X Xextern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt; X Xextern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, X mystch; X Xextern char *cmarg, *cmarg2, **cmlist; Xchar *strcpy(); X X/* I N P U T -- Attempt to read packet number 'pktnum'. */ X X/* X This is the function that feeds input to Kermit's finite state machine. X X If a special start state is in effect, that state is returned as if it were X the type of an incoming packet. Otherwise: X X . If the desired packet arrives within MAXTRY tries, return its type, X with its data stored in the global 'data' array. X X . If the previous packet arrives again, resend the last packet and wait for X another to come in. X X . If the desired packet does not arrive within MAXTRY tries, return indicating X that an error packet should be sent. X*/ X Xinput() { X int len, num, type, numtry; X X if (sstate != 0) { /* If a start state is in effect, */ X type = sstate; /* return it like a packet type, */ X sstate = 0; /* and then nullify it. */ X *data = '\0'; X return(type); X } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ X X/* If it's the same packet we just sent, it's an echo. Read another. */ X X if (type == sndtyp) type = rpack(&len,&num,data); X X chkint(); /* Check for console interrupts. */ X/* X If previous packet again, a timeout pseudopacket, or a bad packet, try again. X*/ X for (numtry = 0; num == prvpkt || type == 'T' || type == 'Q' ; numtry++) X { X if (numtry > MAXTRY) { /* If too many tries, give up */ X strcpy(data,"Timed out."); /* and send a timeout error packet. */ X return('E'); X } X resend(); /* Else, send last packet again, */ X type = rpack(&len,&num,data); /* and try to read a new one. */ X chkint(); /* Look again for interruptions. */ X } X return(type); /* Success, return packet type. */ X} X X/* S P A C K -- Construct and send a packet */ X Xspack(type,num,len,dat) char type, *dat; int num, len; { X int i,j; X X j = dopar(padch); X for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */ X ; X sndpkt[i++] = dopar(mystch); /* Start packet with the start char */ X sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */ X sndpkt[i++] = dopar(tochar(num)); /* The packet number */ X sndpkt[i++] = sndtyp = dopar(type); /* Packet type */ X X for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */ X X sndpkt[i] = '\0'; /* Mark end for block check */ X switch(bctu) { X case 1: /* Type 1 - 6 bit checksum */ X sndpkt[i++] = dopar(tochar(chk1(sndpkt+1))); X break; X case 2: /* Type 2 - 12 bit checksum*/ X j = chk2(sndpkt+1); X sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); X sndpkt[i++] = dopar(tochar(j & 077)); X break; X case 3: /* Type 3 - 16 bit CRC-CCITT */ X j = chk3(sndpkt+1); X sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); X sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); X sndpkt[i++] = dopar(tochar(j & 077)); X break; X } X for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */ X X sndpkt[i++] = dopar(eol); /* EOL character */ X sndpkt[i] = '\0'; /* End of the packet */ X ttol(sndpkt,spktl=i); /* Send the packet just built */ X flco += spktl; /* Count the characters */ X tlco += spktl; X if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */ X screen(type,(long)num,sndpkt); /* Update screen */ X} X X/* D O P A R -- Add an appropriate parity bit to a character */ X Xdopar (ch) char ch; { X int a; X switch (parity) { X case 'm': return(ch | 128); /* Mark */ X case 's': return(ch & 127); /* Space */ X case 'o': ch |= 128; /* Odd (fall thru) */ X case 'e': /* Even */ X a = (ch & 15) ^ ((ch >> 4) & 15); X a = (a & 3) ^ ((a >> 2) & 3); X a = (a & 1) ^ ((a >> 1) & 1); X return(ch | (a << 7)); X default: return(ch); X } X} X X/* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ X Xchk1(pkt) char *pkt; { X int chk; X chk = chk2(pkt); X return((((chk & 0300) >> 6) + chk) & 077); X} X X X/* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ X Xchk2(pkt) char *pkt; { X unsigned int chk; X int p; X for (chk = 0; *pkt != '\0'; *pkt++) { X p = (parity) ? *pkt & 0177 : *pkt; X chk += p; X } X return(chk); X} X X X/* C H K 3 -- Compute a type-3 Kermit block check. */ X/* X Calculate the 16-bit CRC of a null-terminated string using a byte-oriented X tableless algorithm invented by Andy Lowry (Columbia University). The X magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. X Note - this function could adapted for strings containing imbedded 0's X by including a length argument. X*/ Xchk3(s) char *s; { X unsigned int c, q; X LONG crc = 0; X X while ((c = *s++) != '\0') { X if (parity) c &= 0177; X q = (crc ^ c) & 017; /* Low-order nibble */ X crc = (crc >> 4) ^ (q * 010201); X q = (crc ^ (c >> 4)) & 017; /* High order nibble */ X crc = (crc >> 4) ^ (q * 010201); X } X return(crc); X} X X/* Functions for sending various kinds of packets */ X Xack() { /* Send an ordinary acknowledgment. */ X spack('Y',pktnum,0,""); /* No data. */ X nxtpkt(&pktnum); /* Increment the packet number. */ X} /* Note, only call this once! */ X Xack1(s) char *s; { /* Send an ACK with data. */ X spack('Y',pktnum,strlen(s),s); /* Send the packet. */ X nxtpkt(&pktnum); /* Increment the packet number. */ X} /* Only call this once! */ X Xnack() { /* Negative acknowledgment. */ X spack('N',pktnum,0,""); /* NAK's never have data. */ X} X Xresend() { /* Send the old packet again. */ X int w; X X for (w = 0; w < timint - 2; w++) { /* be extra sure no stuff is */ X ttflui(); /* still comming in */ X sleep(1); X if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */ X if (!ttchk() ) break; X } X ttol(sndpkt,spktl); X screen('%',(long)pktnum,sndpkt); X if (pktlog) zsoutl(ZPFILE,sndpkt); X} X Xerrpkt(reason) char *reason; { /* Send an error packet. */ X encstr(reason); X spack('E',pktnum,size,data); X} X Xscmd(t,dat) char t, *dat; { /* Send a packet of the given type */ X encstr(dat); /* Encode the command string */ X ttflui(); /* Flush pending input. */ X spack(t,pktnum,size,data); X} X Xsrinit() { /* Send R (GET) packet */ X encstr(cmarg); /* Encode the filename. */ X ttflui(); /* Flush pending input. */ X spack('R',pktnum,size,data); /* Send the packet. */ X} X Xnxtpkt(num) int *num; { X prvpkt = *num; /* Save previous */ X *num = (*num + 1) % 64; /* Increment packet number mod 64 */ X} X Xsigint() { /* Terminal interrupt handler */ X errpkt("User typed ^C"); X doexit(0); /* Exit with status = 0 */ X} X X/* R P A C K -- Read a Packet */ X Xrpack(l,n,dat) int *l, *n; char *dat; { X int i, j, x, done, pstart, pbl; X char chk[4], xchk[4], t, type; X X chk[3] = xchk[3] = 0; X i = inlin(); /* Read a line */ X if (i != 0) { X debug(F101,"rpack: inlin","",i); X screen('T',(long)pktnum,""); X return('T'); X } X debug(F110,"rpack: inlin ok, recpkt",recpkt,0); X X/* Look for start of packet */ X X for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++) X ; X if (++i >= RBUFL) return('Q'); /* Skip rest if not found */ X X/* now "parse" the packet */ X X debug(F101,"entering rpack with i","",i); X done = 0; X while (!done) { X debug(F101,"rpack starting at i","",i); X pstart = i; /* remember where packet started */ X X/* length */ X X if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */ X X /*** if (t == 2) doexit(0); *** uncomment this to allow ^A^B cause exit ***/ X X if (t == MYEOL) return('Q'); X *l = unchar(t); /* Packet length */ X debug(F101," pkt len","",*l); X X/* sequence number */ X X if ((t = recpkt[i++]) == stchr) continue; X if (t == MYEOL) return('Q'); X *n = unchar(t); X debug(F101,"rpack: n","",*n); X X/* cont'd... */ X X/* ...rpack(), cont'd */ X X X/* type */ X X if ((type = recpkt[i++]) == stchr) continue; X if (type == MYEOL) return('Q'); X debug(F101,"rpack: type","",type); X X if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */ X else if (type == 'N') pbl = *l - 2; /* syncing block check type */ X else pbl = bctu; X X *l -= (pbl + 2); /* Now compute data length */ X debug(F101,"rpack: bctu","",bctu); X debug(F101," pbl","",pbl); X debug(F101," data length","",*l); X X/* data */ X X dat[0] = '\0'; /* Return null string if no data */ X for (j=0; j<*l; i++,j++) X if ((dat[j] = recpkt[i]) == stchr) continue; X else if (dat[j] == MYEOL) return('Q'); X dat[j] = '\0'; X X/* get the block check */ X X debug(F110," packet chk",recpkt+i,0); X for (j = 0; j < pbl; j++) { X chk[j] = recpkt[i]; X debug(F101," chk[j]","",chk[j]); X if (chk[j] == stchr) break; X if (chk[j] == eol) return('Q'); X recpkt[i++] = '\0'; X } X chk[j] = 0; X debug(F111," chk array, j",chk,j); X if (j != pbl) continue; /* Block check right length? */ X done = 1; /* Yes, done. */ X } X X/* cont'd... */ X X/* ...rpack(), cont'd */ X X X/* Got packet, now check the block check */ X X switch (pbl) { X case 1: X xchk[0] = tochar(chk1(&recpkt[pstart])); X if (chk[0] != xchk[0]) { X if (deblog) { X debug(F000,"rpack: chk","",chk[0]); X debug(F000," should be ","",xchk[0]); X } X screen('Q',(long)n,recpkt); X return('Q'); X } X break; X case 2: X x = chk2(&recpkt[pstart]); X xchk[0] = tochar((x & 07700) >> 6); X xchk[1] = tochar(x & 077); X if (deblog) { X debug(F000," xchk[0]","=",xchk[0]); X debug(F000," xchk[1]","=",xchk[1]); X } X if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) { X debug(F100," bct2's don't compare","",0); X screen('Q',(long)n,recpkt); X return('Q'); X } X break; X case 3: X x = chk3(&recpkt[pstart]); X xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12); X xchk[1] = tochar((x & 07700) >> 6); X xchk[2] = tochar(x & 077); X if (deblog) { X debug(F000," xchk[0]","=",xchk[0]); X debug(F000," xchk[1]","=",xchk[1]); X debug(F000," xchk[2]","=",xchk[2]); X } X if ((xchk[0] != chk[0]) || X (xchk[1] != chk[1]) || X (xchk[2] != chk[2])) { X debug(F100," bct3's don't compare","",0); X screen('Q',(long)n,recpkt); X return('Q'); X } X break; X } X X/* Good packet, return its type */ X X ttflui(); /* Done, flush any remaining. */ X screen(type,(long)(*n),recpkt); /* Update screen */ X return(type); X} X X/* I N C H R -- Input character from communication line, with timeout */ X Xinchr(timo) int timo; { X int c; X c = ttinc(timo); X debug(F101,"inchr ttinc","",c); X if (c < 0) return(c); /* Get a character */ X if (parity) c = c & 0177; /* If parity on, discard parity bit. */ X debug(F101," after parity","",c); X return(c); X} X X X/* I N L I N -- Input a line (up to break char) from communication line */ X X/* Returns 0 on success, nonzero on failure */ X Xinlin() { X int e, i, j, k; X X e = (turn) ? turnch : MYEOL; X i = j = k = 0; X if (parity) { X while ((j != e) && (i < RBUFL) && (k < MAXTRY)) { X j = inchr(1); /* Get char, 1 second timeout */ X debug(F101,"inlin inchr","",j); X if (j < 0) k++; /* Timed out. */ X else { X if (j) recpkt[i++] = j; /* Save it */ X k = 0; /* Reset timeout counter. */ X } X } X } else { X i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */ X if (i < 0) k = 1; X } X debug(F111,"inlin",recpkt,i); X debug(F101," timeouts","",k); X if (i < 1) return(1); X if (pktlog) zsoutl(ZPFILE,recpkt); X if (k > MAXTRY) return(1); X tlci += i; /* Count the characters. */ X flci += i; X recpkt[i+1] = '\0'; /* Terminate the input string. */ X return(0); X} !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckusr2.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckusr2.c X/* C K U S R 2 -- "User Interface" STRINGS module for Unix Kermit */ X X/* This module separates long strings from the body of the ckuser module. */ X X#include "ckermi.h" X#include "ckcmd.h" X#include "ckuser.h" X Xextern char cmdbuf[]; Xextern int nrmt, nprm, dfloc; Xextern char *dftty; Xextern struct keytab prmtab[]; Xextern struct keytab remcmd[]; X Xstatic Xchar *hlp1[] = { X"\n", X" Usage: kermit [-x arg [-x arg]...[-yyy]..]]\n", X" x is an option that requires an argument, y an option with no argument:\n", X" actions (* options also require -l and -b) --\n", X" -s file(s) send (use '-s -' to send from stdin)\n", X" -r receive\n", X" -k receive to stdout\n", X" * -g file(s) get remote file(s) from server (quote wildcards)\n", X" -a name alternate name, used with -s, -r, -g\n", X" -x enter server mode\n", X" * -f finish remote server\n", X" * -c connect before transaction\n", X" * -n connect after transaction\n", X" -h help - print this message\n", X" settings --\n", X" -l line communication line device\n", X" -b baud line speed, e.g. 1200\n", X" -i binary file or Unix-to-Unix\n", X" -p x parity, x is one of e,o,m,s,n\n", X" -t line turnaround handshake = xon, half duplex\n", X" -w don't write over preexisting files\n", X" -q be quiet during file transfer\n", X" -d log debugging info to debug.log\n", X" If no action command is included, enter interactive dialog.\n", X"" X}; X X/* U S A G E */ X Xusage() { X conola(hlp1); X} X X/* Help string definitions */ X Xstatic char *tophlp[] = { "\n\ XType ? for a list of commands, type 'help x' for any command x.\n\ XWhile typing commands, use the following special characters:\n\n\ X DEL, RUBOUT, BACKSPACE, CTRL-H: Delete the most recent character typed.\n\ X CTRL-W: Delete the most recent word typed.\n", X X"\ X CTRL-U: Delete the current line.\n\ X CTRL-R: Redisplay the current line.\n\ X ? (question mark) display help on the current command or field.\n\ X ESC (Escape or Altmode) Attempt to complete the current field.\n", X X"\ X \\ (backslash) include the following character literally.\n\n\ XFrom Unix command level, type 'kermit -h' to get help about command line args.\ X\n", X"" }; X Xstatic char *hmxxbye = "\ XShut down and log out a remote Kermit server"; X Xstatic char *hmxxclo = "\ XClose one of the following logs:\n\ X session, transaction, packet, debugging -- 'help log' for further info."; X Xstatic char *hmxxcon = "\ XConnect to a remote system via the tty device given in the\n\ Xmost recent 'set line' command"; X Xstatic char *hmxxget = "\ XFormat: 'get filespec'. Tell the remote Kermit server to send the named\n\ Xfiles. If filespec is omitted, then you are prompted for the remote and\n\ Xlocal filenames separately."; X Xstatic char *hmxxlg[] = { "\ XRecord information in a log file:\n\n\ X debugging Debugging information, to help track down\n\ X (default debug.log) bugs in the C-Kermit program.\n\n\ X packets Kermit packets, to help track down protocol problems.\n\ X (packet.log)\n\n", X X" session Terminal session, during CONNECT command.\n\ X (session.log)\n\n\ X transactions Names and statistics about files transferred.\n\ X (transaction.log)\n", X"" } ; X Xstatic char *hmxxlogi[] = { "\ XSyntax: script text\n\n", X"Login to a remote system using the text provided. The login script\n", X"is intended to operate similarly to uucp \"L.sys\" entries.\n", X"A login script is a sequence of the form:\n\n", X" expect send [expect send] . . .\n\n", X"where 'expect' is a prompt or message to be issued by the remote site, and\n", X"'send' is the names, numbers, etc, to return. The send may also be the\n", X"keyword EOT, to send control-d, or BREAK, to send a break. Letters in\n", X"send may be prefixed by ~ to send special characters. These are:\n", X"~b backspace, ~s space, ~q '?', ~n linefeed, ~r return, ~c don\'t\n", X"append a return, and ~o[o[o]] for octal of a character. As with some \n", X"uucp systems, sent strings are followed by ~r unless they end with ~c.\n\n", X"Only the last 7 characters in each expect are matched. A null expect,\n", X"e.g. ~0 or two adjacent dashes, causes a short delay. If you expect\n", X"that a sequence might not arrive, as with uucp, conditional sequences\n", X"may be expressed in the form:\n\n", X" -send-expect[-send-expect[...]]\n\n", X"where dashed sequences are followed as long as previous expects fail.\n", X"" }; X Xstatic char *hmxxrc[] = { "\ XFormat: 'receive [filespec]'. Wait for a file to arrive from the other\n\ XKermit, which must be given a 'send' command. If the optional filespec is\n", X X"given, the (first) incoming file will be stored under that name, otherwise\n\ Xit will be stored under the name it arrives with.", X"" } ; X Xstatic char *hmxxsen = "\ XFormat: 'send file1 [file2]'. File1 may contain wildcard characters '*' or\n\ X'?'. If no wildcards, then file2 may be used to specify the name file1 is\n\ Xsent under; if file2 is omitted, file1 is sent under its own name."; X Xstatic char *hmxxser = "\ XEnter server mode on the currently selected line. All further commands\n\ Xwill be taken in packet form from the other Kermit program."; X Xstatic char *hmhset = "\ XThe 'set' command is used to establish various communication or file\n\ Xparameters. The 'show' command can be used to display the values of\n\ X'set' parameters. Help is available for each individual parameter;\n\ Xtype 'help set ?' to see what's available.\n"; X Xstatic char *hmxychkt = "\ XType of packet block check to be used for error detection, 1, 2, or 3.\n\ XType 1 is standard, and catches most errors. Types 2 and 3 specify more\n\ Xrigorous checking, at the cost of higher overhead. Not all Kermit programs\n\ Xsupport types 2 and 3.\n"; X Xstatic char *hmxyf[] = { "\ Xset file: names, type, warning, display.\n\n\ X'names' are normally 'converted', which means file names are converted\n\ Xto 'common form' during transmission; 'literal' means use filenames\n\ Xliterally (useful between like Unix systems).\n", X X"\n\ X'type' is normally 'text', in which conversion is done between Unix newlines\n\ Xand CRLF line delimiters; 'binary' means to do no conversion. Use 'binary'\n\ Xfor executable programs or binary data.\n", X X"\n\ X'warning' is 'on' or 'off', normally off. When off, incoming files will\n\ Xoverwrite existing files of the same name. When on, new names will be\n\ Xgiven to incoming files whose names are the same as existing files.\n" , X X"\n\ X'display' is normally 'on', causing file transfer progress to be displayed\n\ Xon your screen when in local mode. 'set display off' is useful for allowing\n\ Xfile transfers to proceed in the background.\n\n", X"" } ; X Xstatic char *hmhrmt[] = { "\ XThe 'remote' command is used to send file management instructions to a\n\ Xremote Kermit server. There should already be a Kermit running in server\n\ Xmode on the other end of the currently selected line. Type 'remote ?' to\n", X X"\ Xsee a list of available remote commands. Type 'help remote x' to get\n\ Xfurther information about a particular remote command 'x'.\n" , X""} ; X X/* D O H L P -- Give a help message */ X Xdohlp(xx) int xx; { X int x,y; X X if (xx < 0) return(xx); X switch (xx) { X Xcase XXBYE: X return(hmsg(hmxxbye)); X Xcase XXCLO: X return(hmsg(hmxxclo)); X Xcase XXCON: X return(hmsg(hmxxcon)); X Xcase XXCWD: X return(hmsg("Change Working Directory, equivalent to Unix 'cd' command")); X Xcase XXDEL: X return(hmsg("Delete a local file or files")); X Xcase XXDIAL: X return(hmsg("Dial a number using modem autodialer")); X Xcase XXDIR: X return(hmsg("Display a directory of local files")); X Xcase XXECH: X return(hmsg("Display the rest of the command on the terminal,\n\ Xuseful in command files.")); X Xcase XXEXI: Xcase XXQUI: X return(hmsg("Exit from the Kermit program, closing any open logs.")); X Xcase XXFIN: X return(hmsg("\ XTell the remote Kermit server to shut down without logging out.")); X Xcase XXGET: X return(hmsg(hmxxget)); X Xcase XXHLP: X return(hmsga(tophlp)); X Xcase XXLOG: X return(hmsga(hmxxlg)); X Xcase XXLOGI: X return(hmsga(hmxxlogi)); X Xcase XXREC: X return(hmsga(hmxxrc)); X Xcase XXREM: X if ((y = cmkey(remcmd,nrmt,"Remote command","")) == -2) return(y); X if (y == -1) return(y); X if (x = (cmcfm()) < 0) return(x); X return(dohrmt(y)); X Xcase XXSEN: X return(hmsg(hmxxsen)); X Xcase XXSER: X return(hmsg(hmxxser)); X Xcase XXSET: X if ((y = cmkey(prmtab,nprm,"Parameter","")) == -2) return(y); X if (y == -2) return(y); X if (x = (cmcfm()) < 0) return(x); X return(dohset(y)); X Xcase XXSHE: X return(hmsg("\ XIssue a command to the Unix shell (space required after '!')")); X Xcase XXSHO: X return(hmsg("\ XDisplay current values of 'set' parameters; 'show version' will display\n\ Xprogram version information for each of the C-Kermit modules.")); X Xcase XXSPA: X return(hmsg("Display disk usage in current device, directory")); X Xcase XXSTA: X return(hmsg("Display statistics about most recent file transfer")); X Xcase XXTAK: X return(hmsg("\ XTake Kermit commands from the named file. Kermit command files may\n\ Xthemselves contain 'take' commands, up to a reasonable depth of nesting.")); X Xdefault: X if (x = (cmcfm()) < 0) return(x); X printf("Not available yet - %s\n",cmdbuf); X break; X } X return(0); X} X X/* H M S G -- Get confirmation, then print the given message */ X Xhmsg(s) char *s; { X int x; X if (x = (cmcfm()) < 0) return(x); X printf("%s\n",s); X return(0); X} X Xhmsga(s) char *s[]; { /* Same function, but for arrays */ X int x, i; X if ( x = (cmcfm()) < 0) return(x); X for ( i = 0; *s[i] ; i++ ) fputs(s[i], stdout); X fputc( '\n', stdout); X return(0); X} X X/* D O H S E T -- Give help for SET command */ X Xdohset(xx) int xx; { X X if (xx == -3) { X printf(hmhset); X return(0); X } X if (xx < 0) return(xx); X switch (xx) { X Xcase XYCHKT: X printf(hmxychkt); X return(0); X Xcase XYDELA: X printf("\ XNumber of seconds to wait before sending first packet after 'send' command\n"); X return(0); X Xcase XYDUPL: X printf("\ XDuring 'connect': 'full' means remote host echoes, 'half' means this program\n\ Xdoes its own echoing.\n"); X return(0); X Xcase XYEOL: X printf("\ XDecimal ASCII value for character to terminate outbound packets, normally\n\ X13 (CR, carriage return). Inbound packets are assumed to end with CR.\n"); X return(0); X Xcase XYESC: X printf("\ XDecimal ASCII value for escape character during 'connect', normally 28\n\ X(Control-\\)\n"); X return(0); X Xcase XYFILE: X printf(hmxyf[0]); X printf(hmxyf[1]); X printf(hmxyf[2]); X printf(hmxyf[3]); X return(0); X Xcase XYFLOW: X printf("\ XType of flow control to be used. Choices are 'xon/xoff' and 'none'.\n\ Xnormally xon/xoff.\n"); X return(0); X Xcase XYHAND: X printf("\ XDecimal ASCII value for character to use for half duplex line turnaround\n\ Xhandshake. Normally, handshaking is not done.\n"); X return(0); X Xcase XYLEN: X printf("\ XPacket length to use. 90 by default. 94 maximum.\n"); X return(0); X Xcase XYLINE: X printf("Device name of communication line to use. Normally %s.\n",dftty); X if (!dfloc) { X printf("If you set the line to other than %s, then Kermit\n",dftty); X printf("\ Xwill be in 'local' mode; 'set line' will reset Kermit to remote mode.\n"); X printf("\ XIf the line has a modem, and if the modem-dialer is set to direct, this \n\ Xcommand causes waiting for a carrier detect (e.g., on a hayes type modem). \n\ XThis can be used to wait for incomming calls. \n"); X printf("\ XTo use the modem to dial out, first set modem-dialer (e.g., to hayes), then \n\ Xset line, next issue the dial command, and finally connect \n"); X } X return(0); X Xcase XYMARK: X printf("\ XDecimal ASCII value of character that marks the beginning of packets sent by\n\ Xthis program (normally 1 = Control-A)\n"); X return(0); X Xcase XYMODM: X printf("\ XType of modem for dialing remote connections. Needed to indicate modem can\n\ Xbe commanded to dial without \"carrier detect\" from modem. Many recently\n\ Xmanufactured modems use \"hayes\" protocol.\n"); X return(0); X Xcase XYNPAD: X printf("\ XNumber of padding characters to request for inbound packets, normally 0.\n"); X return(0); X Xcase XYPADC: X printf("Decimal ASCII value of inbound padding character, normally 0.\n"); X return(0); X Xcase XYPARI: X printf("\ XParity to use during terminal connection and file transfer:\n\ Xeven, odd, mark, space, or none. Normally none.\n"); X return(0); X Xcase XYPROM: X printf("Prompt string for this program, normally 'C-Kermit>'.\n"); X return(0); X Xcase XYSPEE: X printf("\ XCommunication line speed for external tty line specified in most recent\n\ X'set line'. Any of the common baud rates: 0, 110, 150, 300, 600, 1200,\n\ X1800, 2400, 4800, 9600.\n"); X return(0); X Xcase XYTIMO: X printf("\ XTimeout interval for this program to use during file transfer, seconds.\n"); X return(0); X Xdefault: X printf("Not available yet - %s\n",cmdbuf); X return(0); X } X} X X/* D O H R M T -- Give help about REMOTE command */ X Xdohrmt(xx) int xx; { X int x; X if (xx == -3) { X printf(hmhrmt[0]); X printf(hmhrmt[1]); X return(0); X } X if (xx < 0) return(xx); X switch (xx) { X Xcase XZCWD: X return(hmsg("\ XAsk remote Kermit server to change its working directory.")); X Xcase XZDEL: X return(hmsg("\ XAsk remote Kermit server to delete the named file(s).")); X Xcase XZDIR: X return(hmsg("\ XAsk remote Kermit server to provide directory listing of the named file(s).")); X Xcase XZHLP: X return(hmsg("\ XAsk remote Kermit server to tell you what services it provides.")); X Xcase XZHOS: X return(hmsg("\ XSend a command to the remote system in its own command language\n\ Xthrough the remote Kermit server.")); X Xcase XZSPA: X return(hmsg("\ XAsk the remote Kermit server to tell you about its disk space.")); X Xcase XZTYP: X return(hmsg("\ XAsk the remote Kermit server to type the named file(s) on your screen.")); X Xcase XZWHO: X return(hmsg("\ XAsk the remote Kermit server to list who's logged in, or to give information\n\ Xabout the specified user.")); X Xdefault: X if (x = (cmcfm()) < 0) return(x); X printf("not working yet - %s\n",cmdbuf); X return(-2); X } X} !FUNKY!STUFF! echo x - ckusr3.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckusr3.c X/* C K U S R 3 -- "User Interface" for Unix Kermit, part 3 */ X X/* SET and REMOTE commands; screen, debug, interrupt, and logging functions */ X X X/* Includes */ X X#include "ckermi.h" X#include "ckcmd.h" X#include "ckuser.h" X X/* Variables */ X Xextern int size, spsiz, npad, timint, speed, local, server, image, flow, X displa, binary, fncnv, delay, parity, deblog, escape, xargc, X turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, stdouf, X turnch, chklen, bctr, bctu, fsize, dfloc, mdmtyp, X rptflg, ebqflg, warn, quiet, cnflg, timef, mypadn; X Xextern long filcnt, tlci, tlco, ffc, tfc; X Xextern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; Xextern char *cmarg, *cmarg2, **xargv, **cmlist; Xextern char mystch, sstate, mypadc, padch, eol, ctlq, filnam[], ttname[]; Xchar *strcpy(); X X/* Declarations from cmd package */ X Xextern char cmdbuf[]; /* Command buffer */ X X/* From main ckuser module... */ X Xextern char line[100], *lp; /* Character buffer for anything */ Xextern char debfil[50], /* Debugging log file name */ X pktfil[50], /* Packet log file name */ X sesfil[50], /* Session log file name */ X trafil[50]; /* Transaction log file name */ X Xextern int tlevel; /* Take Command file level */ Xextern FILE *tfile[]; /* Array of take command fd's */ X X/* Keyword tables for SET commands */ X X X/* Block checks */ X Xstruct keytab blktab[] = { X "1", 1, 0, X "2", 2, 0, X "3", 3, 0 X}; X X/* Duplex keyword table */ X Xstruct keytab dpxtab[] = { X "full", 0, 0, X "half", 1, 0 X}; X Xstruct keytab filtab[] = { X "display", XYFILD, 0, X "names", XYFILN, 0, X "type", XYFILT, 0, X "warning", XYFILW, 0 X}; Xint nfilp = (sizeof(filtab) / sizeof(struct keytab)); X X/* Flow Control */ X Xstruct keytab flotab[] = { X "none", 0, 0, X "xon/xoff", 1, 0 X}; Xint nflo = (sizeof(flotab) / sizeof(struct keytab)); X X/* Handshake characters */ X Xstruct keytab hshtab[] = { X "bell", 007, 0, X "cr", 015, 0, X "esc", 033, 0, X "lf", 012, 0, X "none", 999, 0, /* (can't use negative numbers) */ X "xoff", 023, 0, X "xon", 021, 0 X}; Xint nhsh = (sizeof(hshtab) / sizeof(struct keytab)); X Xstruct keytab fntab[] = { /* File naming */ X "converted", 1, 0, X "literal", 0, 0 X}; X Xstruct keytab fttab[] = { /* File types */ X "binary", 1, 0, X "text", 0, 0 X}; X Xextern struct keytab mdmtab[] ; /* Modem types (in module ckdial.c) */ Xextern int nmdm; X X X/* Parity keyword table */ X Xstruct keytab partab[] = { X "even", 'e', 0, X "mark", 'm', 0, X "none", 0, 0, X "odd", 'o', 0, X "space", 's', 0 X}; Xint npar = (sizeof(partab) / sizeof(struct keytab)); X X X/* On/Off table */ X Xstruct keytab onoff[] = { X "off", 0, 0, X "on", 1, 0 X}; X X/* D O P R M -- Set a parameter. */ X/* X Returns: X -2: illegal input X -1: reparse needed X 0: success X*/ Xdoprm(xx) int xx; { X int x, y, z; X char *s; X Xswitch (xx) { X Xcase XYLINE: X if ((x = cmtxt("Device name",dftty,&s)) < 0) return(x); X ttclos(); /* close old line, if any was open */ X strcpy(ttname,s); X if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; X if (ttopen(ttname,local,mdmtyp) < 0 ) { /* Can we open the new line? */ X perror("Sorry, can't open line"); X return(-2); /* If not, give bad return */ X } X return(0); X Xcase XYCHKT: X if ((y = cmkey(blktab,3,"","1")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X bctr = y; X return(0); X Xcase XYDEBU: X return(seton(&deblog)); X Xcase XYDELA: X y = cmnum("Number of seconds before starting to send","5",10,&x); X debug(F101,"XYDELA: y","",y); X return(setnum(&delay,x,y)); X Xcase XYDUPL: X if ((y = cmkey(dpxtab,2,"","full")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X duplex = y; X return(0); X Xcase XYEOL: X y = cmnum("Decimal ASCII code for packet terminator","0",10,&x); X y = setcc(&z,x,y); X eol = z; X return(y); X Xcase XYESC: X y = cmnum("Decimal ASCII code for escape character","",10,&x); X return(setcc(&escape,x,y)); X Xcase XYFILE: X if ((y = cmkey(filtab,nfilp,"File parameter","")) < 0) return(y); X switch (y) { X int z; X case XYFILD: /* Display */ X y = seton(&z); X if (y < 0) return(y); X quiet = !z; X return(0); X X case XYFILN: /* Names */ X if ((x = cmkey(fntab,2,"how to handle filenames","converted")) < 0) X return(x); X if ((z = cmcfm()) < 0) return(z); X fncnv = x; X return(0); X X case XYFILT: /* Type */ X if ((x = cmkey(fttab,2,"type of file","text")) < 0) X return(x); X if ((z = cmcfm()) < 0) return(z); X binary = x; X return(0); X X case XYFILW: /* Warning/Write-Protect */ X return(seton(&warn)); X } X Xcase XYFLOW: /* Flow control */ X if ((y = cmkey(flotab,nflo,"","xon/xoff")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X flow = y; X return(0); X Xcase XYHAND: /* Handshake */ X if ((y = cmkey(hshtab,nhsh,"","none")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X turn = (y > 0127) ? 0 : 1 ; X turnch == y; X return(0); X Xcase XYLEN: X y = cmnum("Maximum number of characters in a packet","80",10,&x); X return(setnum(&spsiz,x,y)); X Xcase XYMARK: X y = cmnum("Decimal ASCII code for packet-start character","1",10,&x); X y = setcc(&z,x,y); X mystch = z; X return(y); X Xcase XYMODM: X if ((x=cmkey(mdmtab,nmdm,"type of modem, direct means none","direct")) < 0) X return(x); X if ((z = cmcfm()) < 0) return(z); X mdmtyp = x; X return(0); X Xcase XYNPAD: X y = cmnum("How many padding characters for inbound packets","0",10,&x); X return(setnum(&mypadn,x,y)); X Xcase XYPADC: X y = cmnum("Decimal ASCII code for inbound pad character","0",10,&x); X y = setcc(&z,x,y); X mypadc = z; X return(y); X Xcase XYPARI: X if ((y = cmkey(partab,npar,"","none")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X parity = y; X ebqflg = 1; /* Flag we want 8th-bit prefixing */ X return(0); X Xcase XYPROM: X if ((x = cmtxt("Program's command prompt","C-Kermit>",&s)) < 0) return(x); X cmsetp(s); X return(0); X Xcase XYSPEE: X if (!local) { X printf("\nSpeed setting can only be done on an external line\n"); X printf("You must 'set line' before issuing this command\n"); X return(0); X } X lp = line; X sprintf(lp,"Baud rate for %s",ttname); X if ((y = cmnum(line,"",10,&x)) < 0) return(y); X if (y = (cmcfm()) < 0) return(y); X y = chkspd(x); X if (y < 0) X printf("?Unsupported line speed - %d\n",x); X else { X speed = y; X printf("%s: %d baud\n",ttname,speed); X } X return(0); X Xcase XYTIMO: X y = cmnum("Interpacket timeout interval","5",10,&x); X y = setnum(&timint,x,y); X if (y > -1) timef = 1; X return(y); X Xdefault: X if (x = (cmcfm()) < 0) return(x); X printf("Not working yet - %s\n",cmdbuf); X return(0); X } X} X X/* C H K S P D -- Check if argument is a valid baud rate */ X Xchkspd(x) int x; { X switch (x) { X case 0: X case 110: X case 150: X case 300: X case 600: X case 1200: X case 1800: X case 2400: X case 4800: X case 9600: X return(x); X default: X return(-1); X } X} X X/* S E T O N -- Parse on/off (default on), set parameter to result */ X Xseton(prm) int *prm; { X int x, y; X if ((y = cmkey(onoff,2,"","on")) < 0) return(y); X if ((x = cmcfm()) < 0) return(x); X *prm = y; X return(0); X} X X/* S E T N U M -- Set parameter to result of cmnum() parse. */ X/* X Call with x - number from cnum parse, y - return code from cmnum X*/ Xsetnum(prm,x,y) int x, y, *prm; { X debug(F101,"setnum",y); X if (y < 0) return(y); X if (x > 94) { X printf("\n?Sorry, 94 is the maximum\n"); X return(-2); X } X if ((y = cmcfm()) < 0) return(y); X *prm = x; X return(0); X} X X/* S E T C C -- Set parameter to an ASCII control character value. */ X Xsetcc(prm,x,y) int x, y, *prm; { X if (y < 0) return(y); X if ((x > 037) && (x != 0177)) { X printf("\n?Not in ASCII control range - %d\n",x); X return(-2); X } X if ((y = cmcfm()) < 0) return(y); X *prm = x; X return(0); X} X X/* D O R M T -- Do a remote command */ X Xdormt(xx) int xx; { X int x; X char *s, sbuf[50], *s2; X X if (xx < 0) return(xx); X switch (xx) { X Xcase XZCWD: /* CWD */ X if ((x = cmtxt("Remote directory name","",&s)) < 0) return(x); X debug(F111,"XZCWD: ",s,x); X *sbuf = NUL; X s2 = sbuf; X if (*s != NUL) { /* If directory name given, */ X /* get password on separate line. */ X if (tlevel > -1) { /* From take file... */ X X *line = NUL; X if (fgets(sbuf,50,tfile[tlevel]) == NULL) X ermsg("take file ends prematurely in 'remote cwd'"); X debug(F110," pswd from take file",s2,0); X X } else { /* From terminal... */ X X printf(" Password: "); /* get a password */ X while ((x = getchar()) != '\n') { /* without echo. */ X if ((x &= 0177) == '?') { X printf("? Password of remote directory\n Password: "); X s2 = sbuf; X *sbuf = NUL; X } X else if (x == ESC) /* Mini command line editor... */ X putchar(BEL); X else if (x == BS || x == 0177) X *s2--; X else if (x == 025) { X s2 = sbuf; X *sbuf = NUL; X } X else X *s2++ = x; X } X *s2 = NUL; X putchar('\n'); X } X s2 = sbuf; X } else s2 = ""; X debug(F110," password",s2,0); X sstate = setgen('C',s,s2,""); X return(0); X Xcase XZDEL: /* Delete */ X if ((x = cmtxt("Name of remote file(s) to delete","",&s)) < 0) return(x); X return(sstate = rfilop(s,'E')); X Xcase XZDIR: /* Directory */ X if ((x = cmtxt("Remote directory or file specification","",&s)) < 0) X return(x); X return(sstate = setgen('D',s,"","")); X Xcase XZHLP: /* Help */ X if (x = (cmcfm()) < 0) return(x); X sstate = setgen('H',"","",""); X return(0); X Xcase XZHOS: /* Host */ X if ((x = cmtxt("Command for remote system","",&cmarg)) < 0) return(x); X return(sstate = 'c'); X Xcase XZPRI: /* Print */ X if ((x = cmtxt("Remote file(s) to print on remote printer","",&s)) < 0) X return(x); X return(sstate = rfilop(s,'S')); X Xcase XZSPA: /* Space */ X if ((x = cmtxt("Confirm, or remote directory name","",&s)) < 0) return(x); X return(sstate = setgen('U',s,"","")); X Xcase XZTYP: /* Type */ X if ((x = cmtxt("Remote file specification","",&s)) < 0) return(x); X return(sstate = rfilop(s,'T')); X Xcase XZWHO: X if ((x = cmtxt("Remote user name, or carriage return","",&s)) < 0) X return(x); X return(sstate = setgen('W',s,"","")); X Xdefault: X if (x = (cmcfm()) < 0) return(x); X printf("not working yet - %s\n",cmdbuf); X return(-2); X } X} X X X X/* R F I L O P -- Remote File Operation */ X Xrfilop(s,t) char *s, t; { X if (*s == NUL) { X printf("?File specification required\n"); X return(-2); X } X debug(F111,"rfilop",s,t); X return(setgen(t,s,"","")); X} X X/* S C R E E N -- Screen display function */ X/* X c - a character or small integer X n - an long integer X s - a string. X Fill in this routine with the appropriate display update for the system. X This version is for a dumb tty, and uses the arguments like this: X c: 0 - print s on a new line, followed by a space. X 1 - print s at current screen position. X 2 - print s at current position, followed by newline. X 3 - print "s: n" at current position, followed by newline. X other - print c as a character. X n: if c is 'other', used to decide whether or how to print c. X s: as above. X Horizontal screen position is kept current if screen is only updated by X calling this function. Wraparound is done at column 78. X*/ Xscreen(c,n,s) char c; long n; char *s; { X static int p = 0; /* Screen position */ X int len; char buf[80]; X len = strlen(s); X if (!displa || quiet) return; /* No update if display flag off */ X switch (c) { X case 0: /* Print s on newline */ X conoll(""); /* Start new line, */ X conol(s); /* Print string. */ X conoc(SP); /* Leave a space. */ X p = len + 1; /* Set position counter. */ X return; X case 1: X if (p + len > 78) { conoll(""); p = 0; } X conol(s); if ((p += len) > 78) conoll(""); X return; X case 2: /* Print s, then newline */ X if (p + len > 78) conoll(""); X conoll(s); p = 0; X return; X case 3: X sprintf(buf,"%s: %ld",s,n); conoll(buf); p = 0; X return; X case BS: /* Backspace */ X if (p > 0) p--; X case BEL: /* Beep */ X conoc(c); X return; X default: /* Packet type display */ X if (c == 'Y') return; /* Don't bother with ACKs */ X if (c == 'D') { /* Only show every 4th data packet */ X c = '.'; X if (n % 4) return; X } X if (p++ > 78) { /* If near left margin, */ X conoll(""); /* Start new line */ X p = 0; /* and reset counter. */ X } X conoc(c); /* Display the character. */ X return; X } X} X X/* I N T M S G -- Issue message about terminal interrupts */ X Xintmsg(n) long n; { X extern char *chstr(); X char buf[80]; X X if ((!displa) || (quiet)) return; X#ifdef UXIII X (void) conchk(); /* clear out pending escape-signals in ckxbsd.c */ X#endif X if (n == 1) { X screen(2,0l,""); X#ifdef UXIII X /* we need to signal before kb input */ X sprintf(buf,"Type escape (%s) followed by:",chstr(escape)); X screen(2,0l,buf); X#endif X#ifdef PROVX1 X screen(2,0l,"(transfer cannot be interrupted from keyboard)"); X#else X screen(2,0l,"CTRL-F to cancel file, CTRL-R to resend current packet"); X screen(2,0l,"CTRL-B to cancel batch, CTRL-A for status report..."); X#endif X } X else screen(1,0l," "); X} X X/* C H K I N T -- Check for console interrupts */ X X/*** should rework not to destroy typeahead ***/ X Xchkint() { X int ch, cn; X X if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */ X cn = conchk(); /* Any input waiting? */ X debug(F101,"conchk","",cn); X X while (cn > 0) { /* Yes, read it. */ X cn--; X /* give read 5 seconds for interrupt character */ X if ((ch = coninc(5)) < 0) return(0); X switch (ch & 0177) { X case 0001: /* CTRL-A */ X screen(2,0l,"^A Status report:"); X screen(1,0l, " file type: "); X if (binary) screen(2,0l,"binary"); else screen(2,0l,"text"); X screen(3,filcnt," file number"); X screen(3,ffc, " characters "); X screen(3,(long) bctu, " block check"); X screen(3,(long)rptflg," compression"); X screen(3,(long)ebqflg," 8th-bit prefixing"); X continue; X case 0002: /* CTRL-B */ X screen(1,0l,"^B - Cancelling Batch "); X czseen = 1; X continue; X case 0006: /* CTRL-F */ X screen(1,0l,"^F - Cancelling File "); X cxseen = 1; X continue; X case 0022: /* CTRL-R */ X screen(1,0l,"^R - Resending "); X resend(); X return(1); X default: /* Anything else, just beep */ X screen(BEL,0l,""); X continue; X } X } X return(0); X} X X/* D E B U G -- Enter a record in the debugging log */ X X/* X Call with a format, two strings, and a number: X f - Format, a bit string in range 0-7. X If bit x is on, then argument number x is printed. X s1 - String, argument number 1. If selected, printed as is. X s2 - String, argument number 2. If selected, printed in brackets. X n - Int, argument 3. If selected, printed preceded by equals sign. X X f=0 is special: print s1,s2, and interpret n as a char. X*/ Xdebug(f,s1,s2,n) int f, n; char *s1, *s2; { X static char s[200]; X char *sp = s; X X if (!deblog) return; /* If no debug log, don't */ X switch (f) { X case F000: /* 0, print both strings, */ X sprintf(sp,"%s%s%c\n",s1,s2,n); /* and interpret n as a char */ X zsout(ZDFILE,s); X break; X case F001: /* 1, "=n" */ X sprintf(sp,"=%d\n",n); X zsout(ZDFILE,s); X break; X case F010: /* 2, "[s2]" */ X sprintf(sp,"[%s]\n",s2); X zsout(ZDFILE,""); X break; X case F011: /* 3, "[s2]=n" */ X sprintf(sp,"[%s]=%d\n",s2,n); X zsout(ZDFILE,s); X break; X case F100: /* 4, "s1" */ X zsoutl(ZDFILE,s1); X break; X case F101: /* 5, "s1=n" */ X sprintf(sp,"%s=%d\n",s1,n); X zsout(ZDFILE,s); X break; X case F110: /* 6, "s1[s2]" */ X sprintf(sp,"%s[%s]\n",s1,s2); X zsout(ZDFILE,s); X break; X case F111: /* 7, "s1[s2]=n" */ X sprintf(sp,"%s[%s]=%d\n",s1,s2,n); X zsout(ZDFILE,s); X break; X default: X sprintf(sp,"\n?Invalid format for debug() - %d\n",n); X zsout(ZDFILE,s); X } X} X X/* T L O G -- Log a record in the transaction file */ X/* X Call with a format and 3 arguments: two strings and a number: X f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. X s1 - String, argument number 1. X s2 - String, argument number 2. X n - Int, argument 3. X*/ Xtlog(f,s1,s2,n) int f; long n; char *s1, *s2; { X static char s[200]; X char *sp = s; int x; X X if (!tralog) return; /* If no transaction log, don't */ X switch (f) { X case F000: /* 0 (special) "s1 n s2" */ X sprintf(sp,"%s %ld %s\n",s1,n,s2); X zsout(ZTFILE,s); X break; X case F001: /* 1, " n" */ X sprintf(sp," %ld\n",n); X zsout(ZTFILE,s); X break; X case F010: /* 2, "[s2]" */ X x = strlen(s2); X if (s2[x] == '\n') s2[x] = '\0'; X sprintf(sp,"[%s]\n",s2); X zsout(ZTFILE,""); X break; X case F011: /* 3, "[s2] n" */ X x = strlen(s2); X if (s2[x] == '\n') s2[x] = '\0'; X sprintf(sp,"[%s] %ld\n",s2,n); X zsout(ZTFILE,s); X break; X case F100: /* 4, "s1" */ X zsoutl(ZTFILE,s1); X break; X case F101: /* 5, "s1: n" */ X sprintf(sp,"%s: %ld\n",s1,n); X zsout(ZTFILE,s); X break; X case F110: /* 6, "s1 s2" */ X x = strlen(s2); X if (s2[x] == '\n') s2[x] = '\0'; X sprintf(sp,"%s %s\n",s1,s2); X zsout(ZTFILE,s); X break; X case F111: /* 7, "s1 s2: n" */ X x = strlen(s2); X if (s2[x] == '\n') s2[x] = '\0'; X sprintf(sp,"%s %s: %ld\n",s1,s2,n); X zsout(ZTFILE,s); X break; X default: X sprintf(sp,"\n?Invalid format for tlog() - %ld\n",n); X zsout(ZTFILE,s); X } X} !FUNKY!STUFF! echo x - ckwart.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckwart.c X/* W A R T X * X * pre-process a lex-like file into a C program. X * X * Jeff Damens, Columbia University Center for Computing Activites, 11/84. X * (Reorganized by Frank da Cruz into a single source module for ease X * of distribution). X * Copyright (C) 1984, Trustees of Columbia University. X * May be copied and used except for explicitly commercial purposes. X * X * input format is: X * lines to be copied | %state <state names...> X * %% X * <state> | <state,state,...> CHAR { actions } X * ... X * %% X */ X X#include <stdio.h> X#include <ctype.h> X X/* token types */ X X#define SEP 1 X#define LBRACK 2 X#define RBRACK 3 X#define WORD 4 X#define COMMA 5 X X/* storage sizes */ X X#define MAXSTATES 50 /* max number of states */ X#define MAXWORD 50 /* max # of chars/word */ X#define SBYTES ((MAXSTATES+7)/8) /* # of bytes for state bitmask */ X X/* name of wart function in generated program */ X X#ifndef FNAME X#define FNAME "wart" X#endif X X/* data structure for state information */ X X#ifdef PROVX1 Xtypedef unsigned short CHAR; X#else Xtypedef unsigned char CHAR; X#endif X Xstruct trans { CHAR states[SBYTES]; /* included states */ X int anyst; /* true if this good from any state */ X CHAR inchr; /* input character */ X int actno; /* associated action */ X struct trans *nxt; }; /* next transition */ X Xtypedef struct trans *Trans; X X/* Variables and tables */ X Xint lines,nstates,nacts; X Xchar tokval[MAXWORD]; X Xint tbl[MAXSTATES*128]; X X X Xchar *txt1 = "\n\ X#define BEGIN state =\n\ X\n\ Xint state = 0;\n\ X\n"; X Xchar *fname = FNAME; /* function name goes here */ X X/* rest of program... */ X Xchar *txt2 = "()\n\ X{\n\ X int c,actno;\n\ X extern int tbl[];\n\ X while (1) {\n\ X c = input();\n\ X if ((actno = tbl[c + state*128]) != -1)\n\ X switch(actno) {\n"; X X/* this program's output goes here, followed by final text... */ X Xchar *txt3 = "\n }\n }\n\}\n\n"; X X/* X * turn on the bit associated with the given state X * X */ Xsetstate(state,t) Xint state; XTrans t; X{ X int idx,msk; X idx = state/8; /* byte associated with state */ X msk = 0x80 >> (state % 8); /* bit mask for state */ X t->states[idx] |= msk; X} X X/* X * see if the state is involved in the transition X * X */ X Xteststate(state,t) Xint state; XTrans t; X{ X int idx,msk; X idx = state/8; X msk = 0x80 >> (state % 8); X return(t->states[idx] & msk); X} X X X/* X * read input from here... X * X */ X XTrans Xrdinput(infp,outfp) XFILE *infp,*outfp; X{ X Trans x,rdrules(); X lines = 1; /* line counter */ X nstates = 0; /* no states */ X nacts = 0; /* no actions yet */ X fprintf(outfp,"\n\ X/* WARNING -- This C source program generated by Wart preprocessor. */\n"); X fprintf(outfp,"\ X/* Do not edit this file; edit the Wart-format source file instead, */\n"); X fprintf(outfp,"\ X/* and then run it through Wart to produce a new C source file. */\n\n"); X initial(infp,outfp); /* read state names, initial defs */ X prolog(outfp); /* write out our initial code */ X x = rdrules(infp,outfp); /* read rules */ X epilogue(outfp); /* write out epilogue code */ X return(x); X} X X/* X * initial - read initial definitions and state names. Returns X * on EOF or %%. X * X */ X Xinitial(infp,outfp) XFILE *infp,*outfp; X{ X int c; X char wordbuf[MAXWORD]; X while ((c = getc(infp)) != EOF) { X if (c == '%') { X rdword(infp,wordbuf); X if (strcmp(wordbuf,"states") == 0) X rdstates(infp,outfp); X else if (strcmp(wordbuf,"%") == 0) return; X else fprintf(outfp,"%%%s",wordbuf); X } X else putc(c,outfp); X if (c == '\n') lines++; X } X} X X/* X * boolean function to tell if the given character can be part of X * a word. X * X */ Xisin(s,c) char *s; int c; { X for (; *s != '\0'; s++) X if (*s == c) return(1); X return(0); X} Xisword(c) Xint c; X{ X static char special[] = ".%_-$@"; /* these are allowable */ X return(isalnum(c) || isin(special,c)); X} X X/* X * read the next word into the given buffer. X * X */ Xrdword(fp,buf) XFILE *fp; Xchar *buf; X{ X int len = 0,c; X while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = c; X *buf++ = '\0'; /* tie off word */ X ungetc(c,fp); /* put break char back */ X} X X/* X * read state names, up to a newline. X * X */ X Xrdstates(fp,ofp) XFILE *fp,*ofp; X{ X int c; X char wordbuf[MAXWORD]; X while ((c = getc(fp)) != EOF && c != '\n') X { X if (isspace(c)) continue; /* skip whitespace */ X ungetc(c,fp); /* put char back */ X rdword(fp,wordbuf); /* read the whole word */ X enter(wordbuf,++nstates); /* put into symbol tbl */ X fprintf(ofp,"#define %s %d\n",wordbuf,nstates); X } X lines++; X} X X/* X * allocate a new, empty transition node X * X */ X XTrans Xnewtrans() X{ X Trans new; X int i; X new = (Trans) malloc(sizeof (struct trans)); X for (i=0; i<SBYTES; i++) new->states[i] = 0; X new->anyst = 0; X new->nxt = NULL; X return(new); X} X X/* X * read all the rules. X * X */ X XTrans Xrdrules(fp,out) XFILE *fp,*out; X{ X Trans head,cur,prev; X int curtok,i; X head = cur = NULL; X while ((curtok = gettoken(fp)) != SEP) X X switch(curtok) { X case LBRACK: if (cur == NULL) cur = newtrans(); X else fatal("duplicate state list"); X statelist(fp,cur);/* set states */ X continue; /* prepare to read char */ X X case WORD: if (strlen(tokval) != 1) X fatal("multiple chars in state"); X if (cur == NULL) { X cur = newtrans(); X cur->anyst = 1; X } X cur->actno = ++nacts; X cur->inchr = tokval[0]; X if (head == NULL) head = cur; X else prev->nxt = cur; X prev = cur; X cur = NULL; X copyact(fp,out,nacts); X break; X default: fatal("bad input format"); X } X X return(head); X} X X/* X * read a list of (comma-separated) states, set them in the X * given transition. X * X */ Xstatelist(fp,t) XFILE *fp; XTrans t; X{ X int curtok,sval; X curtok = COMMA; X while (curtok != RBRACK) { X if (curtok != COMMA) fatal("missing comma"); X if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); X if ((sval = lkup(tokval)) == -1) { X fprintf(stderr,"state %s undefined\n",tokval); X fatal("undefined state"); X } X setstate(sval,t); X curtok = gettoken(fp); X } X} X X/* X * copy an action from the input to the output file X * X */ Xcopyact(inp,outp,actno) XFILE *inp,*outp; Xint actno; X{ X int c,bcnt; X fprintf(outp,"case %d:\n",actno); X while ((c = getc(inp)) != '\n' && isspace(c)); /* skip whitespace */ X if (c == '{') { X bcnt = 1; X putc(c,outp); X while (bcnt > 0 && (c = getc(inp)) != EOF) { X if (c == '{') bcnt++; X else if (c == '}') bcnt--; X else if (c == '\n') lines++; X putc(c,outp); X } X if (bcnt > 0) fatal("action doesn't end"); X } X else { X while (c != '\n' && c != EOF) { X putc(c,outp); X c = getc(inp); X } X lines++; X } X fprintf(outp,"\nbreak;\n"); X} X X/* X * find the action associated with a given character and state. X * returns -1 if one can't be found. X * X */ Xfaction(hd,state,chr) XTrans hd; Xint state,chr; X{ X while (hd != NULL) { X if (hd->anyst || teststate(state,hd)) X if (hd->inchr == '.' || hd->inchr == chr) return(hd->actno); X hd = hd->nxt; X } X return(-1); X} X X X/* X * empty the table... X * X */ Xemptytbl() X{ X int i; X for (i=0; i<nstates*128; i++) tbl[i] = -1; X} X X/* X * add the specified action to the output for the given state and chr. X * X */ X Xaddaction(act,state,chr) Xint act,state,chr; X{ X tbl[state*128 + chr] = act; X} X Xwritetbl(fp) XFILE *fp; X{ X warray(fp,"tbl",tbl,128*(nstates+1)); X} X X/* X * write an array to the output file, given its name and size. X * X */ Xwarray(fp,nam,cont,siz) XFILE *fp; Xchar *nam; Xint cont[],siz; X{ X int i; X fprintf(fp,"int %s[] = {\n",nam); X for (i = 0; i < siz; i++) { X fprintf(fp,"%d, ",cont[i]); X if ((i % 20) == 0) putc('\n',fp); X } X fprintf(fp,"};\n"); X} X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X Trans head; X int state,c; X FILE *infile,*outfile; X X if (argc > 1) { X if ((infile = fopen(argv[1],"r")) == NULL) { X fprintf(stderr,"Can't open %s\n",argv[1]); X fatal("unreadable input file"); } } X else infile = stdin; X X if (argc > 2) { X if ((outfile = fopen(argv[2],"w")) == NULL) { X fprintf(stderr,"Can't write to %s\n",argv[2]); X fatal("bad output file"); } } X else outfile = stdout; X X clrhash(); /* empty hash table */ X head = rdinput(infile,outfile); /* read input file */ X emptytbl(); /* empty our tables */ X for (state = 0; state <= nstates; state++) X for (c = 1; c < 128; c++) X addaction(faction(head,state,c),state,c); /* find actions, add to tbl */ X writetbl(outfile); X copyrest(infile,outfile); X printf("%d states, %d actions\n",nstates,nacts); X#ifdef undef X for (state = 1; state <= nstates; state ++) X for (c = 1; c < 128; c++) X if (tbl[state*128 + c] != -1) printf("state %d, chr %d, act %d\n", X state,c,tbl[state*128 + c]); X#endif X exit(0); X} X X/* X * fatal error handler X * X */ X Xfatal(msg) Xchar *msg; X{ X fprintf(stderr,"error in line %d: %s\n",lines,msg); X exit(1); X} X Xprolog(outfp) XFILE *outfp; X{ X int c; X while ((c = *txt1++) != '\0') putc(c,outfp); X while ((c = *fname++) != '\0') putc(c,outfp); X while ((c = *txt2++) != '\0') putc(c,outfp); X} X Xepilogue(outfp) XFILE *outfp; X{ X int c; X while ((c = *txt3++) != '\0') putc(c,outfp); X} X Xcopyrest(in,out) XFILE *in,*out; X{ X int c; X while ((c = getc(in)) != EOF) putc(c,out); X} X X/* X * gettoken - returns token type of next token, sets tokval X * to the string value of the token if appropriate. X * X */ X Xgettoken(fp) XFILE *fp; X{ X int c; X while (1) { /* loop if reading comments... */ X do { X c = getc(fp); X if (c == '\n') lines++; X } while (isspace(c)); /* skip whitespace */ X switch(c) { X case EOF: return(SEP); X case '%': if ((c = getc(fp)) == '%') return(SEP); X tokval[0] = '%'; X tokval[1] = c; X rdword(fp,tokval+2); X return(WORD); X case '<': return(LBRACK); X case '>': return(RBRACK); X case ',': return(COMMA); X case '/': if ((c = getc(fp)) == '*') { X rdcmnt(fp); /* skip over the comment */ X continue; } /* and keep looping */ X else { X ungetc(c); /* put this back into input */ X c = '/'; } /* put character back, fall thru */ X X default: if (isword(c)) { X ungetc(c,fp); X rdword(fp,tokval); X return(WORD); X } X else fatal("Invalid character in input"); X } X } X} X X/* X * skip over a comment X * X */ X Xrdcmnt(fp) XFILE *fp; X{ X int c,star,prcnt; X prcnt = star = 0; /* no star seen yet */ X while (!((c = getc(fp)) == '/' && star)) { X if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); X prcnt = (c == '%'); X star = (c == '*'); X if (c == '\n') lines++; } X} X X X/* X * symbol table management for wart X * X * entry points: X * clrhash - empty hash table. X * enter - enter a name into the symbol table X * lkup - find a name's value in the symbol table. X * X */ X X#define HASHSIZE 101 /* # of entries in hash table */ X Xstruct sym { char *name; /* symbol name */ X int val; /* value */ X struct sym *hnxt; } /* next on collision chain */ X *htab[HASHSIZE]; /* the hash table */ X X X/* X * empty the hash table before using it... X * X */ Xclrhash() X{ X int i; X for (i=0; i<HASHSIZE; i++) htab[i] = NULL; X} X X/* X * compute the value of the hash for a symbol X * X */ Xhash(name) Xchar *name; X{ X int sum; X for (sum = 0; *name != '\0'; name++) sum += (sum + *name); X sum %= HASHSIZE; /* take sum mod hashsize */ X if (sum < 0) sum += HASHSIZE; /* disallow negative hash value */ X return(sum); X} X X/* X * make a private copy of a string... X * X */ Xchar * Xcopy(s) Xchar *s; X{ X char *new; X new = (char *) malloc(strlen(s) + 1); X strcpy(new,s); X return(new); X} X X/* X * enter state name into the hash table X * X */ Xenter(name,svalue) Xchar *name; Xint svalue; X{ X int h; X struct sym *cur; X if (lkup(name) != -1) { X fprintf(stderr,"state %s appears twice...\n"); X exit(1); } X h = hash(name); X cur = (struct sym *)malloc(sizeof (struct sym)); X cur->name = copy(name); X cur->val = svalue; X cur->hnxt = htab[h]; X htab[h] = cur; X} X X/* X * find name in the symbol table, return its value. Returns -1 X * if not found. X * X */ Xlkup(name) Xchar *name; X{ X struct sym *cur; X for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) X if (strcmp(cur->name,name) == 0) return(cur->val); X return(-1); X} !FUNKY!STUFF! echo x - ckmain.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckmain.c Xchar *versio = "C-Kermit 4.2(030) PRERELEASE # 2, 5 March 85"; X X/* C K M A I N -- C-Kermit Main program */ X X/* X Authors: Frank da Cruz, Bill Catchings, Jeff Damens; X Columbia University Center for Computing Activities, 1984-85. X Copyright (C) 1985, Trustees of Columbia University in the City of New York. X Permission is granted to any individual or institution to copy or use this X program except for explicitly commercial purposes, provided this copyright X notice is retained. X*/ X/* X The Kermit file transfer protocol was developed at Columbia University. X It is named after Kermit the Frog, star of the television series THE X MUPPET SHOW; the name is used by permission of Henson Associates, Inc. X "Kermit" is also Celtic for "free". X*/ X/* X Thanks to Herm Fischer, Litton Data Systems, for extensive contributions to X version 4, and to the following people for their contributions over the years: X X Bob Cattani & Chris Maio, Columbia CS Dept X Alan Crosswell, CUCCA X Carl Fongheiser, CWRU X Jim Guyton, Rand Corp X Stan Hanks, Rice U. X Ken Harrenstein, SRI X Steve Hemminger, Tektronix X Tony Movshon, NYU X Ken Poulton, HP Labs X Dave Tweten, NASA Ames X Walter Underwood, Ford Aerospace X Pieter Van Der Linden, Centre Mondial (Paris) X Lauren Weinstein, Vortex X X and many others. X*/ X X#include "ckermi.h" X X/* Text message definitions */ X X#ifndef XENIX X Xchar *hlptxt = "C-Kermit Server\n\ X\n\ XServer Function Customary Command to Invoke the Function\n\ X Who's Logged In? REMOTE WHO [user]\n\ X Help REMOTE HELP\n\ X Finish Serving FINISH\n\ X Send File(s) GET filespec\n\ X Receive File(s) SEND filespec\n\ X Directory Listing REMOTE DIRECTORY [filespec]\n\ X Change Directory REMOTE CWD [directory]\n\ X Type File(s) REMOTE TYPE filespec\n\ X Delete File(s) REMOTE DELETE filespec\n\ X Disk Usage Query REMOTE SPACE [directory]\n\ X Unix Shell Command REMOTE HOST command-string\n\ X\n\0"; X X#else X Xchar *hlptxt = "C-Kermit Server Commands Supported:\n\ X\n\ XGET filespec REMOTE CWD [directory] REMOTE SPACE [directory]\n\ XSEND filespec REMOTE DIRECTORY [filespec] REMOTE HOST command-string\n\ XFINISH REMOTE DELETE filespec REMOTE WHO [user]\n\ XREMOTE HELP REMOTE TYPE filespec\n\ X\n\0"; X X#endif X Xchar *srvtxt = "\r\n\ XC-Kermit server starting. Return to your local machine by typing\r\n\ Xits escape sequence for closing the connection, and issue further\r\n\ Xcommands from there. To shut down the C-Kermit server, issue the\r\n\ XFINISH command and then reconnect.\n\ X\r\n\0"; X X/* Declarations for Send-Init Parameters */ X Xint spsiz = DSPSIZ, /* maximum packet size we can send */ X timint = DMYTIM, /* My timeout interval */ X timef = 0, /* Flag for override packet timeout */ X npad = MYPADN, /* How much padding to send */ X mypadn = MYPADN, /* How much padding to ask for */ X chklen = 1, /* Length of block check */ X bctr = 1, /* Block check type requested */ X bctu = 1, /* Block check type used */ X ebq = MYEBQ, /* 8th bit prefix */ X ebqflg = 0, /* 8th-bit quoting flag */ X rpt = 0, /* Repeat count */ X rptq = MYRPTQ, /* Repeat prefix */ X rptflg = 0, /* Repeat processing flag */ X capas = 0; /* Capabilities */ X Xchar padch = MYPADC, /* Padding character to send */ X mypadc = MYPADC, /* Padding character to ask for */ X eol = MYEOL, /* End-Of-Line character to send */ X ctlq = CTLQ, /* Control prefix in incoming data */ X myctlq = CTLQ; /* Outbound control character prefix */ X X X/* Packet-related variables */ X Xint pktnum = 0, /* Current packet number */ X prvpkt = -1, /* Previous packet number */ X sndtyp, /* Type of packet just sent */ X size, /* Current size of output pkt data */ X osize, /* Previous output packet data size */ X maxsize, /* Max size for building data field */ X spktl; /* Length packet being sent */ X Xchar sndpkt[MAXPACK*2], /* Entire packet being sent */ X recpkt[RBUFL], /* Packet most recently received */ X data[MAXPACK+4], /* Packet data buffer */ X srvcmd[MAXPACK*2], /* Where to decode server command */ X *srvptr, /* Pointer to above */ X mystch = SOH, /* Outbound packet-start character */ X stchr = SOH; /* Incoming packet-start character */ X X/* File-related variables */ X Xchar filnam[50]; /* Name of current file. */ X Xint nfils, /* Number of files in file group */ X fsize; /* Size of current file */ X X/* Communication line variables */ X Xchar ttname[50]; /* Name of communication line. */ X Xint parity, /* Parity specified, 0,'e','o',etc */ X flow, /* Flow control, 1 = xon/xoff */ X speed = -1, /* Line speed */ X turn = 0, /* Line turnaround handshake flag */ X turnch = XON, /* Line turnaround character */ X duplex = 0, /* Duplex, full by default */ X escape = 034, /* Escape character for connect */ X delay = DDELAY, /* Initial delay before sending */ X mdmtyp = 0; /* Type of modem 1=hayes 2=ventel */ X X X/* Statistics variables */ X Xlong filcnt, /* Number of files in transaction */ X flci, /* Characters from line, current file */ X flco, /* Chars to line, current file */ X tlci, /* Chars from line in transaction */ X tlco, /* Chars to line in transaction */ X ffc, /* Chars to/from current file */ X tfc; /* Chars to/from files in transaction */ X X/* Flags */ X Xint deblog = 0, /* Flag for debug logging */ X pktlog = 0, /* Flag for packet logging */ X seslog = 0, /* Session logging */ X tralog = 0, /* Transaction logging */ X displa = 0, /* File transfer display on/off */ X stdouf = 0, /* Flag for output to stdout */ X xflg = 0, /* Flag for X instead of F packet */ X hcflg = 0, /* Doing Host command */ X fncnv = 1, /* Flag for file name conversion */ X binary = 0, /* Flag for binary file */ X warn = 0, /* Flag for file warning */ X quiet = 0, /* Be quiet during file transfer */ X local = 0, /* Flag for external tty vs stdout */ X server = 0, /* Flag for being a server */ X cnflg = 0, /* Connect after transaction */ X cxseen = 0, /* Flag for cancelling a file */ X czseen = 0; /* Flag for cancelling file group */ X X/* Variables passed from command parser to protocol module */ X Xchar sstate = 0; /* Starting state for automaton */ Xchar *cmarg = ""; /* Pointer to command data */ Xchar *cmarg2 = ""; /* Pointer to second data field */ Xchar **cmlist; /* Pointer to file list in argv */ X X/* Miscellaneous */ X Xchar **xargv; /* Global copies of argv */ Xint xargc; /* and argc */ X Xextern char *dftty; /* Default tty name from ckx???.c */ Xextern int dfloc; /* Default location: remote/local */ Xextern int dfprty; /* Default parity */ Xextern int dfflow; /* Default flow control */ X X X/* M A I N -- C-Kermit main program */ X Xmain(argc,argv) int argc; char **argv; { X X char *strcpy(); X X/* Do some initialization */ X X xargc = argc; /* Make global copies of argc */ X xargv = argv; /* ...and argv. */ X sstate = 0; /* No default start state. */ X strcpy(ttname,dftty); /* Set up default tty name. */ X local = dfloc; /* And whether it's local or remote. */ X parity = dfprty; /* Set initial parity, */ X flow = dfflow; /* and flow control. */ X X/* Look for a UNIX-style command line... */ X X if (argc > 1) { /* Command line arguments? */ X sstate = cmdlin(); /* Yes, parse. */ X if (sstate) { X proto(); /* Take any requested action, then */ X if (!quiet) conoll(""); /* put cursor back at left margin, */ X if (cnflg) conect(); /* connect if requested, */ X doexit(0); /* and then exit with status 0. */ X } X } X X/* If no action requested on command line, enter interactive parser */ X X cmdini(); /* Initialize command parser */ X while(sstate = parser()) { /* Loop getting commands. */ X if (sstate) proto(); /* Enter protocol if requested. */ X } X} !FUNKY!STUFF! echo x - cklogi.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > cklogi.c Xchar *loginv = "Login Command for Unix, V1.0(003) 28 Feb 85"; X X/* C K L O G I -- Login script for logging onto remote system */ X X/* X This module should work under all versions of Unix. It calls externally X defined system-depended functions for i/o. X X The module expects a login string of the expect send [expect send] ... X format. It is intended to operate similarly to the way the common X uucp "L.sys" login entries work. Conditional responses are supported X expect[-send-expect[...]] as with uucp. The send keyword EOT sends a X control-d, and the keyword BREAK sends a break. Letters prefixed X by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, X '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'', X '~"', '~c' don't append return, '~o[o[o]]' octal character. As with X some uucp systems, sent strings are followed by ~r (not ~n) unless they X end with ~c. Null expect strings (e.g., ~0 or --) cause a short X delay, and are useful for sending sequences requiring slight pauses. X X Author: Herm Fischer, Litton Data Systems, Van Nuys CA (HFISCHER@USC-ECLB) X*/ X X#include "ckermi.h" X#include <signal.h> X#include <setjmp.h> X Xextern int local, speed, flow, seslog, mdmtyp; Xextern char ttname[]; Xstatic char * chstr(); X X#define EXP_ALRM 15 /* Time to wait for expect string */ X#define SND_ALRM 15 /* Time to allow for sending string */ X#define NULL_EXP 2 /* Time to pause on null expect strg*/ X X#define SBUFL 300 /* Login Sequence buffer */ Xstatic char seq_buf[SBUFL], *s; Xstatic int got_it, no_cr; X X/* connect state parent/child communication signal handlers */ X Xstatic jmp_buf alrmRng; /* Envir ptr for connect errors */ X Xstatic XtimeInt() { /* modem read failure handler, */ X longjmp(alrmRng,1); /* notifies parent process to stop */ X} X X/* X Sequence interpreter -- pick up next sequence from command string, X decode escapes and place into seq_buf X*/ Xstatic Xsequenc() { X X int i; X char c, oct_char; X X no_cr = 0; /* output needs cr appended */ X X for (i=0; i<SBUFL; ) { X if (*s == '\0' || *s == '-' || *s == ' ') { /* done */ X seq_buf[i] = '\0'; X return ; X } X X if (*s == '~') { /* escape character */ X switch (c = *(++s) ) { X case 'n': seq_buf[i++] = '\n'; break; X case 'r': seq_buf[i++] = '\r'; break; X case 't': seq_buf[i++] = '\t'; break; X case 'b': seq_buf[i++] = '\b'; break; X case 'q': seq_buf[i++] = '?'; break; X case '~': seq_buf[i++] = '~'; break; X case '\'': seq_buf[i++] = '\''; break; X case '\"': seq_buf[i++] = '\"'; break; X case 's': seq_buf[i++] = ' '; break; X case 'c': no_cr = 1; break; X default: X if ( isdigit(c) ) { /* octal character */ X oct_char = (c & 7); /* most significant digit */ X if (isdigit( *(s+1) ) ) { X oct_char = (oct_char<<3) | ( (*(++s)) & 7 ) ; X if (isdigit( *(s+1) ) ) { X oct_char = (oct_char<<3) | ( (*(++s)) & 7 ) ; X } X } X seq_buf[i++] = oct_char; X break; X } X } X } X else seq_buf[i++] = *s; /* plain old character */ X s++; X } X seq_buf[i] = '\0'; X return; /* end of space, return anyway */ X} X X/* X Receive sequence -- see if expected response comes return success X (or failure) in got_it X*/ Xstatic XrecvSeq() { X X char *e, got[7], trace[300]; X int i, l; X X sequenc(); X l = strlen(e=seq_buf); /* no more than 7 chars allowed */ X if (l > 7) { X e += l-7; X l = 7; X } X X tlog(F111,"expecting sequence",e,(long) l); X if (l == 0) { /* null sequence, just delay a little */ X sleep (NULL_EXP); X got_it = 1; X tlog(F100,"got it (null sequence)","",0l); X return; X } X *trace = '\0'; X for (i=0; i<7; i++) got[i]='\0'; X X signal(SIGALRM,timeInt); /* did we get it? */ X if (!setjmp(alrmRng)) { /* not timed out yet */ X alarm(EXP_ALRM); X while (!got_it) { X for (i=0; i<(l-1); i++) got[i] = got[i+1]; /* shift over one */ X got[l-1] = ttinc(0) & 0177; /* next char */ X if (strlen(trace) < sizeof(trace)-2 ) X strcat(trace,chstr(got[l-1])); X got_it = (!strncmp(seq_buf, got, l) ) ; X } X } else got_it = 0; /* timed out here */ X X alarm(0); X signal(SIGALRM,SIG_IGN); X tlog(F110,"received sequence: ",trace,0l); X tlog(F101,"returning with got-it code","",(long) got_it); X return; X} X X/* X Output A Sequence starting at pointer s, X return 0 if okay, X 1 if failed to read (modem hangup or whatever) X*/ Xstatic int XoutSeq() { X char *sb; X int l; X X sequenc(); X l = strlen(seq_buf); X tlog(F111,"sending sequence ",seq_buf,(long) l); X signal(SIGALRM,timeInt); X if (!setjmp(alrmRng)) { X alarm(SND_ALRM); X if (!strcmp(seq_buf,"EOT")) ttoc(dopar('\004')); X else if (!strcmp(seq_buf,"BREAK")) ttsndb(); X else { X if (l > 0) { X for ( sb=seq_buf; *sb; sb++) *sb = dopar(*sb); X ttol(seq_buf,l); /* with parity */ X } X if (!no_cr) ttoc( dopar('\r') ); X } X alarm(0); X signal(SIGALRM,SIG_IGN); X return(0); X } X alarm(0); /* else -- alarm rang */ X signal(SIGALRM,SIG_IGN); X return( -1 ); X} X X/* L O G I N -- Login to remote system */ X Xlogin(cmdstr) char *cmdstr; { X X int (*saveAlm)(); /* save incomming alarm function */ X char *e; X X s = cmdstr; /* make global to cklogi.c */ X X tlog(F100,loginv,"",0l); X X if (!local) { X printf("Sorry, you must 'set line' first\n"); X return(-2); X } X if (speed < 0) { X printf("Sorry, you must 'set speed' first\n"); X return(-2); X } X if (ttopen(ttname,local,mdmtyp) < 0) { X sprintf(seq_buf,"Sorry, can't open %s",ttname); X perror(seq_buf); X return(-2); X } X printf("Logging on thru %s, speed %d.\r\n",ttname,speed); X *seq_buf=0; X for (e=s; *e; e++) strcat(seq_buf, chstr(*e) ); X printf("The logon string is: %s\r\n",seq_buf); X tlog(F110,"Logon command string: ",seq_buf, 0l); X X/* Condition console terminal and communication line */ X X if (ttvt(speed,flow) < 0) { X printf("Sorry, Can't condition communication line\n"); X return(-2); X } X /* save initial timer interrupt value */ X saveAlm = signal(SIGALRM,SIG_IGN); X X ttflui(); /* flush stale input */ X X/* cont'd... */ X X/* ...login, cont'd */ X X/* start expect - send sequence */ X X while (*s) { /* while not done with buffer */ X X while (*s && *s == ' ') s++; /* skip over separating blanks */ X /* gather up expect sequence */ X got_it = 0; X recvSeq(); X X while (!got_it) { X /* no, is there a conditional send */ X if (*s++ != '-') goto failRet; /* no -- return failure */ X X /* start of conditional send */ X ttflui(); /* flush out input buffer */ X if (outSeq()) goto failRet; /* if unable to send! */ X X if (*s++ != '-') goto failRet; /* must have condit respon.*/ X recvSeq(); X } /* loop back and check got_it */ X X while (*s && *s++ != ' ') ; /* skip over conditionals and spaces */ X ttflui(); /* Flush */ X if (*s) if (outSeq()) goto failRet; /* if any */ X } X signal(SIGALRM,saveAlm); X printf("Logged on!\r\n"); X tlog(F100,"Logged on!","",0l); X return(0); X XfailRet: X signal(SIGALRM,saveAlm); X printf("Sorry, logon failed\r\n"); X tlog(F100,"Logon failed","",0l); X return(-2); X} X X X/* C H S T R -- Make printable string from a character */ X Xstatic char * Xchstr(c) char c; { X static char sc[4]; X X if (c < SP) sprintf(sc, "^%c",ctl(c) ); X else sprintf(sc, "%c", c); X X return(sc); X} !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckxunx.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckxunx.c Xchar *ckxv = "Unix tty I/O, 4.2(016), 5 Mar 85"; X X/* C-Kermit interrupt, terminal control & i/o functions for Unix systems */ X X/* F. da Cruz, Columbia University Center for Computing Activities */ X X#ifdef BSD4 Xchar *ckxsys = " 4.2 BSD"; X#endif X X#ifdef PROVX1 Xchar *ckxsys = " Pro-3xx Venix 1.0"; X#endif X X/* Tower support contributed by John Bray, Auburn University */ X#ifdef TOWER1 Xchar *ckxsys = " NCR Tower 1632, OS 1.02"; X#endif X X/* Sys III/V, Xenix, PC/IX support by Herm Fischer, Litton Data Systems */ X#ifdef UXIII X#ifdef XENIX Xchar *ckxsys = " Xenix/286"; X#else X#ifdef PCIX Xchar *ckxsys = " PC/IX"; X#else X#ifdef ISIII Xchar *ckxsys = " Interactive Systems Corp System III"; X#else Xchar *ckxsys = " AT&T System III/System V"; X#endif X#endif X#endif X#endif X X/* X Note - KERLD is the Berkeley Unix Berknet line driver, modified to pass X through all 8 bits, and to allow an arbitrary break character to be set. X Don't define this symbol unless you have made this modification to your X 4.2BSD kernel! X*/ X#ifdef BSD4 X/* #define KERLD */ /* <-- note, commented out */ X#endif X X/* X Variables available to outside world: X X dftty -- Pointer to default tty name string, like "/dev/tty". X dfloc -- 0 if dftty is console, 1 if external line. X dfprty -- Default parity X dfflow -- Default flow control X ckxech -- Flag for who echoes console typein: X 1 - The program (system echo is turned off) X 0 - The system (or front end, or terminal). X functions that want to do their own echoing should check this flag X before doing so. X X flfnam -- Name of lock file, including its path, e.g., X "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77" X hasLock -- Flag set if this kermit established a uucp lock. X inbufc -- number of tty line rawmode unread characters X (system III/V unixes) X backgrd -- Flag indicating program executing in background ( & on X end of shell command). Used to ignore INT and QUIT signals. X X Functions for assigned communication line (either external or console tty): X X ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access. X ttclos() -- Close & reset the tty, releasing any access lock. X ttpkt(speed,flow) -- Put the tty in packet mode and set the speed. X ttvt(speed,flow) -- Put the tty in virtual terminal mode. X or in DIALING or CONNECTED modem control state. X ttinl(dest,max,timo) -- Timed read line from the tty. X ttinc(timo) -- Timed read character from tty. X myread() -- System 3 raw mode bulk buffer read, gives X -- subsequent chars one at a time and simulates X -- FIONREAD! X myunrd(c) -- Places c back in buffer to be read (one only) X ttchk() -- See how many characters in tty input buffer. X ttxin(n,buf) -- Read n characters from tty (untimed). X ttol(string,length) -- Write a string to the tty. X ttoc(c) -- Write a character to the tty. X ttflui() -- Flush tty input buffer. X X ttlock(ttname) -- Lock against uucp collisions (Sys III) X ttunlck() -- Unlock " " " X look4lk(ttname) -- Check if a lock file exists X*/ X X/* XFunctions for console terminal: X X congm() -- Get console terminal modes. X concb(esc) -- Put the console in single-character wakeup mode with no echo. X conbin(esc) -- Put the console in binary (raw) mode. X conres() -- Restore the console to mode obtained by congm(). X conoc(c) -- Unbuffered output, one character to console. X conol(s) -- Unbuffered output, null-terminated string to the console. X conola(s) -- Unbuffered output, array of strings to the console. X conxo(n,s) -- Unbuffered output, n characters to the console. X conchk() -- Check if characters available at console (bsd 4.2). X Check if escape char (^\) typed at console (System III/V). X coninc(timo) -- Timed get a character from the console. X conint() -- Enable terminal interrupts on the console if not background. X connoi() -- Disable terminal interrupts on the console if not background. X XTime functions X X msleep(m) -- Millisecond sleep X ztime(&s) -- Return pointer to date/time string X*/ X X/* Includes */ X X#include <stdio.h> /* Unix Standard i/o */ X#include <signal.h> /* Interrupts */ X#include <setjmp.h> /* Longjumps */ X X#ifdef UXIII X#include <sys/types.h> X#endif X X#ifndef PROVX1 X#include <sys/file.h> /* File information */ X#endif X X#ifndef DIRSIZ X#ifdef MAXNAMLEN X#define DIRSIZ MAXNAMLEN X#else X#define DIRSIZ 14 X#endif X#endif X X#ifdef UXIII X#include <termio.h> X#include <sys/ioctl.h> X#include <fcntl.h> /* directory reading for locking */ X#include <sys/dir.h> X#include <errno.h> /* error numbers for system returns */ Xextern int errno; /* system call error return */ X#endif X X#ifndef UXIII X#include <sgtty.h> /* Set/Get tty modes */ X#ifndef PROVX1 X#include <sys/time.h> /* Clock info (for break generation) */ X#endif X#endif X X#ifdef TOWER1 X#include <sys/timeb.h> /* Clock info for NCR Tower */ X#endif X X#include "ckdebu.h" /* Formats for debug() */ X X/* Declarations */ X X/* dftty is the device name of the default device for file transfer */ X/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */ X X#ifdef PROVX1 X char *dftty = "/dev/com1"; X int dfloc = 1; X#else X char *dftty = "/dev/tty"; X int dfloc = 0; X#endif X X int dfprty = 0; /* Parity (0 = none) */ X int dfflow = 1; /* Xon/Xoff flow control */ X int backgrd = 0; /* Assume in foreground (no '&' ) */ X Xint ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ X X/* Declarations of variables global within this module */ X Xstatic jmp_buf sjbuf; /* Longjump buffer */ Xstatic int lkf = 0, /* Line lock flag */ X conif = 0, /* Console interrupts on/off flag */ X cgmf = 0, /* Flag that console modes saved */ X xlocal = 0, /* Flag for tty local or remote */ X ttyfd = -1; /* TTY file descriptor */ Xstatic char escchr; /* Escape or attn character */ X X#ifdef KERLD X static int kerld = 1; /* Special Kermit line discipline... */ X struct tchars oldc, newc; /* Special characters */ X int ld = NETLDISC; /* Special Kermit line discipline */ X int oldld; /* Old discipline */ X#else X static int kerld = 0; /* for 4.2BSD only, */ X#endif X X#ifdef BSD4 X static struct timeval tv; /* For getting time, from sys/time.h */ X static struct timezone tz; X#endif X X#ifdef TOWER1 Xstatic long clock; /* For getting time from sys/time.h */ Xstatic struct timeb ftp; /* And from sys/timeb.h */ X#endif X X#ifdef UXIII X static struct termio /* sgtty info... */ X ttold, ttraw, tttvt, /* for communication line */ X ccold, ccraw, cccbrk; /* and for console */ X#else X static struct sgttyb /* sgtty info... */ X ttold, ttraw, tttvt, /* for communication line */ X ccold, ccraw, cccbrk; /* and for console */ X#endif X Xstatic char flfnam[80]; /* uucp lock file path name */ Xstatic int hasLock = 0; /* =1 if this kermit locked uucp */ Xstatic int inbufc = 0; /* stuff for efficient SIII raw line */ Xstatic int ungotn = -1; /* pushback to unread character */ Xstatic int conesc = 0; /* set to 1 if esc char (^\) typed */ X Xstatic int ttlock(); /* definition of ttlock subprocedure */ Xstatic int ttunlck(); /* unlock subprocedure */ X X/* T T O P E N -- Open a tty for exclusive access. */ X X/* Returns 0 on success, -1 on failure. */ X Xttopen(ttname,lcl,modem) char *ttname; int lcl, modem; { X X if (ttyfd > -1) return(0); /* If already open, ignore this call */ X xlocal = lcl; /* Make available to other functions */ X#ifndef UXIII X ttyfd = open(ttname,2); /* Open a tty for read/write */ X#else X /* if modem connection, don't wait for carrier */ X ttyfd = open(ttname,O_RDWR | (modem ? O_NDELAY : 0) ); X#endif X if (ttyfd < 0) return(-1); X lkf = 0; X X#ifndef PROVX1 X if (xlocal) { X#ifdef BSD4 X if ((flock(ttyfd,(LOCK_EX|LOCK_NB)) < 0) || (ttlock(ttname) < 0 )) { X#else X#ifdef TOWER1 X if (ioctl(ttyfd,TIOCEXCL, NULL) < 0) { X#else X if (ttlock(ttname) < 0) { X#endif X#endif X fprintf(stderr,"Sorry - Exclusive access to %s was denied\n",ttname); X return(-1); /* Can't open if already locked */ X } else lkf = 1; X } X#endif X X#ifndef UXIII X gtty(ttyfd,&ttold); /* Get sgtty info */ X gtty(ttyfd,&ttraw); /* And a copy of it for packets*/ X gtty(ttyfd,&tttvt); /* And one for virtual tty service */ X#else X ioctl(ttyfd,TCGETA,&ttold); /* Same deal for Sys III, Sys V */ X ioctl(ttyfd,TCGETA,&ttraw); X ioctl(ttyfd,TCGETA,&tttvt); X#endif X debug(F101,"ttopen, ttyfd","",ttyfd); X debug(F111," lock file",flfnam,lkf); X return(0); X} X X/* T T C L O S -- Close the TTY, releasing any lock. */ X Xttclos() { X if (ttyfd < 0) return(0); /* Wasn't open. */ X#ifndef PROVX1 X#ifdef BSD4 X if (lkf) flock(ttyfd,LOCK_UN); /* Unlock it first. */ X#endif X if (xlocal) ttunlck(); X#endif X ttres(); /* Reset modes. */ X close(ttyfd); /* Close it. */ X ttyfd = -1; /* Mark it as closed. */ X return(0); X} X X X/* T T R E S -- Restore terminal to "normal" mode. */ X Xttres() { /* Restore the tty to normal. */ X if (ttyfd < 0) return(-1); /* Not open. */ X sleep(1); /* Wait for pending i/o to finish. */ X#ifdef KERLD X if (kerld) ioctl(ttyfd,TIOCSETD,&oldld); /* Restore old line discipline. */ X#endif X#ifdef UXIII X if (ioctl(ttyfd,TCSETA,&ttold) < 0) return(-1); /* restore termio stuff */ X#else X debug(F101,"ttres, ttyfd","",ttyfd); X if (stty(ttyfd,&ttold) < 0) return(-1); /* Restore sgtty stuff */ X#endif X#ifdef KERLD X if (kerld) ioctl(ttyfd,TIOCSETC,&oldc); /* Restore old special chars. */ X#endif X X return(0); X} X X#ifndef PROVX1 X X/* Exclusive uucp file locking control */ X/* X by H. Fischer, creative non-Bell coding ! X*/ Xstatic char * Xxxlast(s,c) char *s; char c; { /* Equivalent to strrchr() */ X int i; X for (i = strlen(s); i > 0; i--) X if ( s[i-1] == c ) return( s + (i - 1) ); X return(NULL); X} Xstatic Xlook4lk(ttname) char *ttname; { X extern char *strcat(), *strcpy(); X char *device, *devname; X char lockfil[DIRSIZ+1]; X X#ifdef ISIII X char *lockdir = "/etc/locks"; X#else X char *lockdir = "/usr/spool/uucp"; X#endif X X device = ( (devname=xxlast(ttname,'/')) != NULL ? devname+1 : ttname); X X#ifdef ISIII X (void) strcpy( lockfil, device ); X#else X (void) strcat( strcpy( lockfil, "LCK.." ), device ); X#endif X X if (access( lockdir, 04 ) < 0) { /* read access denied on lock dir */ X fprintf(stderr,"Warning, read access to lock directory denied\n"); X return( 1 ); /* cannot check or set lock file */ X } X X (void) strcat(strcat(strcpy(flfnam,lockdir),"/"), lockfil); X debug(F110,"look4lk",flfnam,0); X X if ( ! access( flfnam, 00 ) ) { /* print out lock file entry */ X char lckcmd[40] ; X (void) strcat( strcpy(lckcmd, "ls -l ") , flfnam); X system(lckcmd); X return( -1 ); X } X if ( access( lockdir, 02 ) < 0 ) { /* lock file cannot be written */ X fprintf(stderr,"Warning, write access to lock directory denied\n"); X return( 1 ); X } X return( 0 ); /* okay to go ahead and lock */ X} X X/* T T L O C K */ X Xstatic Xttlock(ttyfd) char *ttyfd; { /* lock uucp if possible */ X int lck_fil, l4l; X X hasLock = 0; /* not locked yet */ X if ((l4l=look4lk(ttyfd)) < 0) return(-1); /* already locked */ X if (l4l == 1) return (0); /* can't read/write lock directory */ X if ((lck_fil=open (flfnam, O_CREAT | O_EXCL)) < 1 ) X return(-1); /* failed to create */ X close (lck_fil); X hasLock = 1; /* now is locked */ X return(0); X} X X/* T T U N L O C K */ X Xstatic Xttunlck() { /* kill uucp lock if possible */ X if (hasLock) unlink( flfnam ); X} X#endif X X X X/* T T P K T -- Condition the communication line for packets. */ X/* or for modem dialing */ X X#define DIALING 4 /* flags (via flow) for modem handling */ X#define CONNECT 5 X X/* If called with speed > -1, also set the speed. */ X X/* Returns 0 on success, -1 on failure. */ X Xttpkt(speed,flow) int speed, flow; { X extern char ttname[]; X int s; X if (ttyfd < 0) return(-1); /* Not open. */ X X#ifdef KERLD X if (kerld) { X ioctl(ttyfd,TIOCGETD,&oldld); /* Get line discipline */ X ioctl(ttyfd,TIOCGETC,&oldc); /* Get special chars */ X newc = oldc; /* Copy special chars */ X newc.t_brkc = '\r'; /* Set CR to be break character */ X if(ioctl(ttyfd,TIOCSETC,&newc) < 0) return(-1); X } X#endif X X/* cont'd... */ X X/* ...ttpkt(), cont'd */ X X X/* Note, KERLD ignores the TANDEM, ECHO, and CRMOD bits */ X X s = ttsspd(speed); /* Check the speed */ X X#ifndef UXIII X if (flow == 1) ttraw.sg_flags |= TANDEM; /* Use XON/XOFF if selected */ X if (flow == 0) ttraw.sg_flags &= ~TANDEM; X ttraw.sg_flags |= RAW; /* Go into raw mode */ X ttraw.sg_flags &= ~(ECHO|CRMOD); /* Use CR for break character */ X#ifdef TOWER1 X ttraw.sg_flags &= ~ANYP; /* Must tell Tower no parityr */ X#endif X if (s > -1) ttraw.sg_ispeed = ttraw.sg_ospeed = s; /* Do the speed */ X if (stty(ttyfd,&ttraw) < 0) return(-1); /* Set the new modes. */ X#endif X X#ifdef UXIII X if (flow == 1) ttraw.c_iflag |= (IXON|IXOFF); X if (flow == 0) ttraw.c_iflag &= ~(IXON|IXOFF); X X if (flow == DIALING) ttraw.c_cflag |= CLOCAL|HUPCL; X if (flow == CONNECT) ttraw.c_cflag &= ~CLOCAL; X X ttraw.c_lflag &= ~(ICANON|ECHO); X ttraw.c_lflag |= ISIG; /* do check for interrupt */ X ttraw.c_iflag |= (BRKINT|IGNPAR); X ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC); X ttraw.c_oflag &= ~(ONLCR|OCRNL|ONLRET); X ttraw.c_cc[4] = 1; X ttraw.c_cc[5] = 0; X X if (s > -1) ttraw.c_cflag &= ~CBAUD, ttraw.c_cflag |= s; /* set speed */ X X if (ioctl(ttyfd,TCSETA,&ttraw) < 0) return(-1); /* set new modes . */ X if (flow == DIALING) { X if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 ) X return(-1); X close( open(ttname,2) ); /* magic to force file open!!! */ X } X#endif X X#ifdef KERLD X if (kerld) { X if (ioctl(ttyfd,TIOCSETD,&ld) < 0) X return(-1); /* Set line discpline. */ X } X#endif X X ttflui(); /* Flush any pending input */ X return(0); X} X X/* T T V T -- Condition communication line for use as virtual terminal */ X Xttvt(speed,flow) int speed, flow; { X extern char ttname[]; X int s; X if (ttyfd < 0) return(-1); /* Not open. */ X X s = ttsspd(speed); /* Check the speed */ X X#ifndef UXIII X if (flow == 1) tttvt.sg_flags |= TANDEM; /* XON/XOFF if selected */ X if (flow == 0) tttvt.sg_flags &= ~TANDEM; X tttvt.sg_flags |= RAW; /* Raw mode */ X#ifdef TOWER1 X tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or system III ??? parity */ X#else X tttvt.sg_flags &= ~ECHO; /* No echo */ X#endif X if (s > -1) tttvt.sg_ispeed = tttvt.sg_ospeed = s; /* Do the speed */ X X/* NOTE-- bsd code needs clocal and o_Ndelay stuff here */ X return(stty(ttyfd,&tttvt)); X#else X if (flow == 1) tttvt.c_iflag |= (IXON|IXOFF); X if (flow == 0) tttvt.c_iflag &= ~(IXON|IXOFF); X X if (flow == DIALING) tttvt.c_cflag |= CLOCAL|HUPCL; X if (flow == CONNECT) tttvt.c_cflag &= ~CLOCAL; X X tttvt.c_lflag &= ~(ISIG|ICANON|ECHO); X tttvt.c_iflag |= (IGNBRK|BRKINT|IGNPAR); X tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC); X tttvt.c_oflag &= ~(ONLCR|OCRNL|ONLRET); X tttvt.c_cc[4] = 1; X tttvt.c_cc[5] = 0; X X if (s > -1) tttvt.c_cflag &= ~CBAUD, tttvt.c_cflag |= s; /* set speed */ X X if (ioctl(ttyfd,TCSETA,&tttvt) < 0) return(-1); /* set new modes . */ X if (flow == DIALING) { X if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 ) X return(-1); X close( open(ttname,2) ); /* magic to force file open!!! */ X } X return(0); X#endif X} X X/* T T S S P D -- Return the internal baud rate code for 'speed'. */ X Xttsspd(speed) { X int s, spdok; X X if (speed < 0) return(-1); X spdok = 1; /* Assume arg ok */ X switch (speed) { X case 0: s = B0; break; /* Just the common ones. */ X case 110: s = B110; break; /* The others from ttydev.h */ X case 150: s = B150; break; /* could also be included if */ X case 300: s = B300; break; /* necessary... */ X case 600: s = B600; break; X case 1200: s = B1200; break; X case 1800: s = B1800; break; X case 2400: s = B2400; break; X case 4800: s = B4800; break; X case 9600: s = B9600; break; X default: X spdok = 0; X fprintf(stderr,"Unsupported line speed - %d\n",speed); X fprintf(stderr,"Current speed not changed\n"); X break; X } X if (spdok) return(s); else return(-1); X } X X X X/* T T F L U I -- Flush tty input buffer */ X Xttflui() { X X#ifndef PROVX1 X long n; X#endif X if (ttyfd < 0) return(-1); /* Not open. */ X X#ifdef BSD4 X#ifdef TOWER1 X n = FREAD; /* Specify read queue */ X if (ioctl(ttyfd,TIOCFLUSH,&n) < 0) perror("flush failed"); X#endif X#endif X X#ifdef UXIII X inbufc = 0; X ungotn = -1; X if (ioctl(ttyfd,TCFLSH,0) < 0) perror("flush failed"); X#endif X X return(0); X} X X/* Interrupt Functions */ X X X/* Timeout handler for communication line input functions */ X Xtimerh() { X longjmp(sjbuf,1); X} X X X/* Set up terminal interrupts on console terminal */ X X#ifdef UXIII Xesctrp() { /* trap console escapes (^\) */ X conesc = 1; X signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ X} X#endif X X X/* C O N I N T -- Console Interrupt setter */ X Xconint(f) int (*f)(); { /* Set an interrupt trap. */ X X if (backgrd) return; /* must ignore signals in bkgrd */ X X#ifdef UXIII X signal(SIGQUIT,esctrp); /* console escape in pkt modes */ X if (conesc) { /* clear out pending escapes */ X conesc = 0; X } X#endif X X if (conif) return; /* Nothing to do if already on. */ X X/* check if invoked in background -- if so signals set to be ignored */ X X if (signal(SIGINT,SIG_IGN) == SIG_IGN) { X backgrd = 1; /* means running in background */ X#ifdef UXIII X signal(SIGQUIT,SIG_IGN); /* must leave signals ignored */ X#endif X return; X } X signal(SIGINT,f); /* Function to trap to. */ X conif = 1; /* Flag console interrupts on. */ X} X X X/* C O N N O I -- Reset console terminal interrupts */ X Xconnoi() { /* Console-no-interrupts */ X X if (backgrd) return; /* must ignore signals in bkgrd */ X X signal(SIGINT,SIG_DFL); X conif = 0; X} X X/* myread() -- System III raw read buffer to block input up */ X Xmyread() { /* return character or -1 if disconnected */ X X static int inbuf_item; X static CHAR inbuf[257]; X CHAR readit; X X if (ungotn >= 0) readit = ungotn; X else { X if (inbufc > 0) X readit = inbuf[++inbuf_item]; X else { X if ((inbufc=read(ttyfd,inbuf,256)) == 0 ) return(-1); X readit = inbuf[inbuf_item=0]; X } X inbufc--; X } X ungotn = -1; X return(readit ); X } X Xmyunrd(ch) CHAR ch; { /* push back up to one character */ X ungotn = ch; X} X X X/* T T C H K -- Tell how many characters are waiting in tty input buffer */ X Xttchk() { X#ifndef PROVX1 X int n, x; X#ifdef BSD4 X x = ioctl(ttyfd, FIONREAD, &n); X return((x < 0) ? 0 : n); X#else X return(inbufc + (ungotn >= 0) ); X#endif X#else X return(0); X#endif X} X X X/* T T X I N -- Get n characters from tty input buffer */ X Xttxin(n,buf) int n; char *buf; { X int x; X#ifndef UXIII X x = read(ttyfd,buf,n); X#else X for( x=0; x<n; buf[x++]=myread() ); X#endif X if (x > 0) buf[x] = '\0'; X return(x); X} X X/* T T O L -- Similar to "ttinl", but for writing. */ X Xttol(s,n) int n; char *s; { X int x; X if (ttyfd < 0) return(-1); /* Not open. */ X x = write(ttyfd,s,n); X debug(F111,"ttol",s,n); X if (x < 0) debug(F101,"ttol failed","",x); X return(x); X} X X X/* T T O C -- Output a character to the communication line */ X Xttoc(c) char c; { X if (ttyfd < 0) return(-1); /* Not open. */ X return(write(ttyfd,&c,1)); X} X X/* T T I N L -- Read a record (up to break character) from comm line. */ X/* X If no break character encountered within "max", return "max" characters, X with disposition of any remaining characters undefined. Otherwise, return X the characters that were read, including the break character, in "dest" and X the number of characters read as the value of function, or 0 upon end of X file, or -1 if an error occurred. Times out & returns error if not completed X within "timo" seconds. X*/ X Xttinl(dest,max,timo,eol) int max,timo; char *dest; { X int x, y, c; X if (ttyfd < 0) return(-1); /* Not open. */ X if (timo <= 0) { /* Untimed. */ X#ifndef UXIII X x = read(ttyfd,dest,max); /* Try to read. */ X#else X for (x = c = 0; (x < max) && (c != eol); x++) { X c = myread(); X dest[x] = c; X } X#endif X return(x); /* Return the count. */ X } X signal(SIGALRM,timerh); /* Timed, set up timeout action. */ X alarm(timo); /* Set the timer. */ X if (setjmp(sjbuf)) x = -1; /* Do this if timer went off. */ X else if (kerld) { X x = read(ttyfd,dest,max); /* Try to read. */ X } else { X for (x = c = y = 0; (x < max) && (c != eol); x++) { X#ifndef UXIII X while ( !(y = read(ttyfd,&c,1))) ; /* skip null reads */ X if (y < 0) return(y); X#else X c = myread(); X#endif X dest[x] = c; X } X x++; X } X alarm(0); /* Success, turn off timer, */ X signal(SIGALRM,SIG_DFL); /* and associated interrupt. */ X return(x); /* Return the count. */ X} X X/* T T I N C -- Read a character from the communication line */ X Xttinc(timo) int timo; { X int n; X CHAR ch; X X if (ttyfd < 0) return(-1); /* Not open. */ X if (timo <= 0) { /* Untimed. */ X#ifndef UXIII X while ( !(n = read(ttyfd,&ch,1)) ) ; /* Wait for a character. */ X return( (n > 0) ? (ch & 0377) : n ); X#else X /* comm line failure returns -1 thru myread, so don't &= 0377 */ X return( myread() ); X#endif X } X X signal(SIGALRM,timerh); /* Timed, set up timer. */ X alarm(timo); X if (setjmp(sjbuf)) n = -1; X else { X#ifndef UXIII X n = read(ttyfd,&ch,1); /* Read a character. */ X#else X ch = myread(); X n = 1; X#endif X } X alarm(0); /* Turn off timer, */ X signal(SIGALRM,SIG_DFL); /* and interrupt. */ X if (n > 0) return(ch & 0377); else return(n); /* Return char or -1. */ X} X X/* T T S N D B -- Send a BREAK signal */ X Xttsndb() { X int x; X X if (ttyfd < 0) return(-1); /* Not open. */ X X#ifdef PROVX1 X/*** insert code to set speed to 50 baud and send 2-3 nulls ***/ X return(0); X#else X#ifdef UXIII X if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) { /* Turn on BREAK */ X conol("Can't send BREAK"); X return(-1); X } X return(0); X#else X#ifdef BSD4 X if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */ X conol("Can't send BREAK"); X return(-1); X } X x = msleep(275); /* Sleep for so many milliseconds */ X if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */ X conol("BREAK stuck!!!"); X doexit(1); /* Get out, closing the line. */ X /* with exit status = 1 */ X } X return(x); X#endif X#endif X#endif X} X X/* M S L E E P -- Millisecond version of sleep(). */ X X/* X Intended only for small intervals. For big ones, just use sleep(). X*/ X Xmsleep(m) int m; { X X#ifdef PROVX1 X sleep(1+m/1000.0); X return(0); X#endif X X#ifdef BSD4 X int t1, t3, t4; X if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */ X t1 = tv.tv_sec; /* Seconds */ X Xif (0) { /* Old way (works) */ X while (1) { X gettimeofday(&tv, &tz); X t3 = tv.tv_sec - t1; X t4 = (tv.tv_usec + 1000000 * t3) / 1000; X if (t4 > m) return(t4); X } X} else { /* New way (also works) */ X tv.tv_sec = 0; X tv.tv_usec = m * 1000; X return(select( 0, (int *)0, (int *)0, (int *)0, &tv) ); X} X#endif X X#ifdef TOWER1 X if (ftime(&ftp) < 0) return(-1); /* Get current time. */ X t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm; X while (1) { X ftime(&ftp); /* new time */ X t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1; X if (t3 > m) return (t3); X } X#endif X} X X/* Z T I M E -- Return date/time string */ X Xztime(s) char **s; { X X#ifdef UXIII X extern long time(); /* Sys III/V way to do it */ X char *ctime(); X long clock_storage; X X clock_storage = time( (long *) 0 ); X *s = ctime( &clock_storage ); X#endif X X#ifdef PROVX1 X int utime[2]; /* Venix way */ X time(utime); X *s = ctime(utime); X#endif X X#ifdef BSD4 X char *asctime(); /* Berkeley way */ X struct tm *localtime(); X struct tm *tp; X X gettimeofday(&tv, &tz); X time(&tv.tv_sec); X tp = localtime(&tv.tv_sec); X *s = asctime(tp); X#endif X X#ifdef TOWER1 X char *asctime(); /* Tower way */ X struct tm *localtime(); X struct tm *tp; X X time(&clock); X tp = localtime(&clock); X *s = asctime(tp); X#endif X} X X/* C O N G M -- Get console terminal modes. */ X X/* X Saves current console mode, and establishes variables for switching between X current (presumably normal) mode and other modes. X*/ X Xcongm() { X#ifndef UXIII X gtty(0,&ccold); /* Structure for restoring */ X gtty(0,&cccbrk); /* For setting CBREAK mode */ X gtty(0,&ccraw); /* For setting RAW mode */ X#else X ioctl(0,TCGETA,&ccold); X ioctl(0,TCGETA,&cccbrk); X ioctl(0,TCGETA,&ccraw); X#endif X cgmf = 1; /* Flag that we got them. */ X} X X X/* C O N C B -- Put console in cbreak mode. */ X X/* Returns 0 if ok, -1 if not */ X Xconcb(esc) char esc; { X int x; X if (cgmf == 0) congm(); /* Get modes if necessary. */ X escchr = esc; /* Make this available to other fns */ X ckxech = 1; /* Program can echo characters */ X#ifndef UXIII X cccbrk.sg_flags |= CBREAK; /* Set to character wakeup, */ X cccbrk.sg_flags &= ~ECHO; /* no echo. */ X x = stty(0,&cccbrk); X#else X cccbrk.c_lflag &= ~(ICANON|ECHO); X cccbrk.c_cc[0] = 003; /* interrupt char is control-c */ X cccbrk.c_cc[1] = escchr; /* escape during packet modes */ X cccbrk.c_cc[4] = 1; X cccbrk.c_cc[5] = 1; X x = ioctl(0,TCSETA,&cccbrk); /* set new modes . */ X#endif X if (x > -1) setbuf(stdout,NULL); /* Make console unbuffered. */ X return(x); X} X X/* C O N B I N -- Put console in binary mode */ X X X/* Returns 0 if ok, -1 if not */ X Xconbin(esc) char esc; { X if (cgmf == 0) congm(); /* Get modes if necessary. */ X escchr = esc; /* Make this available to other fns */ X ckxech = 1; /* Program can echo characters */ X#ifndef UXIII X ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF */ X ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */ X return(stty(0,&ccraw)); X#else X ccraw.c_lflag &= ~(ISIG|ICANON|ECHO); X ccraw.c_iflag |= (BRKINT|IGNPAR); X ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF); X ccraw.c_oflag &= ~(ONLCR|OCRNL|ONLRET); X ccraw.c_cc[4] = 1; X ccraw.c_cc[5] = 1; X return(ioctl(0,TCSETA,&ccraw) ); /* set new modes . */ X#endif X} X X X/* C O N R E S -- Restore the console terminal */ X Xconres() { X if (cgmf == 0) return(0); /* Don't do anything if modes */ X sleep(1); /* not known! */ X ckxech = 0; /* System should echo chars */ X#ifndef UXIII X return(stty(0,&ccold)); /* Restore controlling tty */ X#else X return(ioctl(0,TCSETA,&ccold)); X#endif X} X X/* C O N O C -- Output a character to the console terminal */ X Xconoc(c) char c; { X write(1,&c,1); X} X X/* C O N X O -- Write x characters to the console terminal */ X Xconxo(x,s) char *s; int x; { X write(1,s,x); X} X X/* C O N O L -- Write a line to the console terminal */ X Xconol(s) char *s; { X int len; X len = strlen(s); X write(1,s,len); X} X X/* C O N O L A -- Write an array of lines to the console terminal */ X Xconola(s) char *s[]; { X int i; X for (i=0 ; *s[i] ; i++) conol(s[i]); X} X X/* C O N O L L -- Output a string followed by CRLF */ X Xconoll(s) char *s; { X conol(s); X write(1,"\r\n",2); X} X X X/* C O N C H K -- Check if characters available at console */ X Xconchk() { X#ifdef PROVX1 X return(0); X#else X int n, x; X#ifndef UXIII X x = ioctl(0, FIONREAD, &n); X return((x < 0) ? 0 : n); X#else X if (conesc) { /* Escape typed */ X conesc = 0; X signal(SIGQUIT,esctrp); /* restore escape */ X return(1); X } X return(0); X#endif X#endif X} X X/* C O N I N C -- Get a character from the console */ X Xconinc(timo) int timo; { X int n = 0; char ch; X if (timo <= 0 ) { /* untimed */ X n = read(0, &ch, 1); /* Read a character. */ X ch &= 0377; X if (n > 0) return(ch); /* Return the char if read */ X else X#ifdef UXIII X if (n < 0 && errno == EINTR) /* if read was interrupted by QUIT */ X return(escchr); /* user entered escape character */ X else /* couldnt be ^c, sigint never returns */ X#endif X return(-1); /* Return the char, or -1. */ X } X signal(SIGALRM,timerh); /* timed, set up timer */ X alarm(timo); X if (setjmp(sjbuf)) n = -2; X else { X n = read(0, &ch, 1); X alarm(0); X signal(SIGALRM,SIG_DFL); /* stop timing, we got our character */ X ch &= 0377; X } X if (n > 0) return(ch); X else X#ifdef UXIII X if (n == -1 && errno == EINTR) /* If read interrupted by QUIT, */ X return(escchr); /* user entered escape character, */ X else /* can't be ^c, sigint never returns */ X#endif X return(-1); X} !FUNKY!STUFF! echo x - ckzunx.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckzunx.c Xchar *ckzv = "Unix file support, 4.1(015) 28 Feb 85"; X X/* C K Z B S D -- Kermit file system support for Unix systems */ X X/* F. da Cruz, Columbia University Center for Computing Activities */ X X/* Berkeley Unix Version 4.x */ X#ifdef BSD4 Xchar *ckzsys = " 4.x BSD"; X#endif X X/* DEC Professional-300 series with Venturcom Venix 1.0 */ X#ifdef PROVX1 Xchar *ckzsys = " DEC Pro-3xx/Venix 1.0"; X#endif X X/* NCR Tower support contributed by Kevin O'Kane, U. of Tennessee */ X/* Tower OS is like Sys III but with BSD features -- mostly follows BSD */ X#ifdef TOWER1 Xchar *ckxsys = " NCR Tower 1632, OS 1.02"; X#endif X X/* Sys III/V, Xenix, PC/IX,... support by Herm Fischer, Litton Data Systems */ X#ifdef UXIII X#ifdef XENIX Xchar *ckzsys = " Xenix/286"; X#else X#ifdef PCIX Xchar *ckzsys = " PC/IX"; X#else X#ifdef ISIII Xchar *ckzsys = " Interactive Systems Corp, System III"; X#else Xchar *ckzsys = " AT&T System III/System V"; X#endif X#endif X#endif X#endif X X/* Definitions of some Unix system commands */ X Xchar *DIRCMD = "ls -l "; /* For directory listing */ Xchar *DELCMD = "rm -f "; /* For file deletion */ Xchar *TYPCMD = "cat "; /* For typing a file */ X X#ifdef BSD4 Xchar *SPACMD = "pwd ; quota ; df ."; /* Space/quota of current directory */ X#else Xchar *SPACMD = "df "; X#endif X Xchar *SPACM2 = "df "; /* For space in specified directory */ X X#ifdef BSD4 Xchar *WHOCMD = "finger "; /* For seeing who's logged in */ X#else Xchar *WHOCMD = "who "; /* For seeing who's logged in */ X#endif X X/* X Functions (n is one of the predefined file numbers from ckermi.h): X X zopeni(n,name) -- Opens an existing file for input. X zopeno(n,name) -- Opens a new file for output. X zclose(n) -- Closes a file. X zchin(n) -- Gets the next character from an input file. X zsout(n,s) -- Write a null-terminated string to output file, buffered. X zsoutl(n,s) -- Like zsout, but appends a line terminator. X zsoutx(n,s,x) -- Write x characters to output file, unbuffered. X zchout(n,c) -- Add a character to an output file, unbuffered. X zchki(name) -- Check if named file exists and is readable, return size. X zchko(name) -- Check if named file can be created. X znewn(name,s) -- Make a new unique file name based on the given name. X zdelet(name) -- Delete the named file. X zxpand(string) -- Expands the given wildcard string into a list of files. X znext(string) -- Returns the next file from the list in "string". X zxcmd(cmd) -- Execute the command in a lower fork. X zclosf() -- Close input file associated with zxcmd()'s lower fork. X zrtol(n1,n2) -- Convert remote filename into local form. X zltor(n1,n2) -- Convert local filename into remote form. X zchdir(dirnam) -- Change working directory. X zhome() -- Return pointer to home directory name string. X */ X X/* Includes */ X X#include "ckermi.h" /* Kermit definitions, ctype, stdio */ X#include <sys/types.h> /* Data types */ X#include <sys/dir.h> /* Directory structure */ X#include <sys/stat.h> /* File status */ X#include <pwd.h> /* Password file for shell name */ X X#ifndef PROVX1 X#include <sys/file.h> /* File access */ X#endif X X/* Some systems define these in include files, others don't... */ X X#ifndef R_OK X#define R_OK 4 /* For access */ X#endif X X#ifndef W_OK X#define W_OK 2 X#endif X X#ifdef PROVX1 X#define MAXNAMLEN DIRSIZ /* Max file name length */ X#endif X X#ifdef UXIII X#include <fcntl.h> X#define MAXNAMLEN DIRSIZ X#endif X X#ifndef O_RDONLY X#define O_RDONLY 000 X#endif X X#ifndef MAXNAMLEN X#define MAXNAMLEN 14 /* If still not defined... */ X#endif X X#define MAXWLD 500 /* Maximum wildcard filenames */ X X X/* Declarations */ X XFILE *fp[ZNFILS] = { /* File pointers */ X NULL, NULL, NULL, NULL, NULL, NULL, NULL }; X Xstatic int pid; /* pid of child fork */ Xstatic int fcount; /* Number of files in wild group */ Xchar *getenv(), *strcpy(); /* For finding home directory */ Xextern errno; /* System error code */ X Xstatic char *mtchs[MAXWLD], /* Matches found for filename */ X **mtchptr; /* Pointer to current match */ X X/* Z O P E N I -- Open an existing file for input. */ X Xzopeni(n,name) int n; char *name; { X debug(F111," zopeni",name,n); X debug(F101," fp","",(int) fp[n]); X if (chkfn(n) != 0) return(0); X if (n == ZSTDIO) { /* Standard input? */ X if (isatty(0)) { X fprintf(stderr,"?Terminal input not allowed\n"); X debug(F110,"zopeni: attempts input from unredirected stdin","",0); X return(0); X } X fp[ZIFILE] = stdin; X return(1); X } X fp[n] = fopen(name,"r"); /* Real file. */ X debug(F111," zopeni", name, (int) fp[n]); X if (fp[n] == NULL) perror("zopeni"); X return((fp[n] != NULL) ? 1 : 0); X} X X/* Z O P E N O -- Open a new file for output. */ X Xzopeno(n,name) int n; char *name; { X debug(F111," zopeno",name,n); X if (chkfn(n) != 0) return(0); X if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ X fp[ZOFILE] = stdout; X debug(F101," fp[]=stdout", "", (int) fp[n]); X return(1); X } X fp[n] = fopen(name,"w"); /* A real file */ X if (fp[n] == NULL) perror("zopeno"); X if (n == ZDFILE) setbuf(fp[n],NULL); /* Make debugging file unbuffered */ X debug(F101, " fp[n]", "", (int) fp[n]); X return((fp[n] != NULL) ? 1 : 0); X} X X/* Z C L O S E -- Close the given file. */ X Xzclose(n) int n; { X if (chkfn(n) < 1) return(0); X if ((fp[n] != stdout) && (fp[n] != stdin)) fclose(fp[n]); X fp[n] = NULL; X return(1); X} X X/* Z C H I N -- Get a character from the input file. */ X Xzchin(n) int n; { X int a; X if (chkfn(n) < 1) return(-1); X a = getc(fp[n]); X return((a == EOF) ? -1 : a & 0377); X} X X/* Z S O U T -- Write a string to the given file, buffered. */ X Xzsout(n,s) int n; char *s; { X if (chkfn(n) < 1) return(-1); X fprintf(fp[n],s); X return(0); X} X X/* Z S O U T L -- Write string to file, with line terminator, buffered */ X Xzsoutl(n,s) int n; char *s; { X if (chkfn(n) < 1) return(-1); X fprintf(fp[n],"%s\n",s); X return(0); X} X X/* Z S O U T X -- Write x characters to file, unbuffered. */ X Xzsoutx(n,s,x) int n, x; char *s; { X if (chkfn(n) < 1) return(-1); X return(write(fp[n]->_file,s,x)); X} X X X/* Z C H O U T -- Add a character to the given file. */ X Xzchout(n,c) int n; char c; { X if (chkfn(n) < 1) return(-1); X if (n == ZSFILE) X return(write(fp[n]->_file,&c,1)); /* Use unbuffered for session log */ X else { X putc(c,fp[n]); /* Buffered for everything else */ X return(0); X } X} X X/* C H K F N -- Internal function to verify file number is ok */ X X/* X Returns: X -1: File number n is out of range X 0: n is in range, but file is not open X 1: n in range and file is open X*/ Xchkfn(n) int n; { X switch (n) { X case ZCTERM: X case ZSTDIO: X case ZIFILE: X case ZOFILE: X case ZDFILE: X case ZTFILE: X case ZPFILE: X case ZSFILE: break; X default: X debug(F101,"chkfn: file number out of range","",n); X fprintf(stderr,"?File number out of range - %d\n",n); X return(-1); X } X return( (fp[n] == NULL) ? 0 : 1 ); X} X X/* Z C H K I -- Check if input file exists and is readable */ X X/* X Returns: X >= 0 if the file can be read (returns the size). X -1 if file doesn't exist or can't be accessed, X -2 if file exists but is not readable (e.g. a directory file). X -3 if file exists but protected against read access. X*/ X/* X For Berkeley Unix, a file must be of type "regular" to be readable. X Directory files, special files, and symbolic links are not readable. X*/ Xzchki(name) char *name; { X struct stat buf; X int x; X X x = stat(name,&buf); X if (x < 0) { X debug(F111,"zchki stat fails",name,errno); X return(-1); X } X x = buf.st_mode & S_IFMT; /* Isolate file format field */ X if (x != S_IFREG) { X debug(F111,"zchki skipping:",name,x); X return(-2); X } X debug(F111,"zchki stat ok:",name,x); X X if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */ X debug(F111," access failed:",name,x); /* No */ X return(-3); X } else { X x = buf.st_size; X debug(F111," access ok:",name,x); /* Yes */ X return( (x > -1) ? x : 0 ); X } X} X X/* Z C H K O -- Check if output file can be created */ X X/* X Returns -1 if write permission for the file would be denied, 0 otherwise. X*/ Xzchko(name) char *name; { X int i, x; X char s[50], *sp; X X sp = s; /* Make a copy, get length */ X x = 0; X while ((*sp++ = *name++) != '\0') X x++; X if (x == 0) return(-1); /* If no filename, fail. */ X X debug(F101," length","",x); X for (i = x; i > 0; i--) /* Strip filename. */ X if (s[i-1] == '/') break; X X debug(F101," i","",i); X if (i == 0) /* If no path, use current directory */ X strcpy(s,"./"); X else /* Otherwise, use given one. */ X s[i] = '\0'; X X x = access(s,W_OK); /* Check access of path. */ X if (x < 0) { X debug(F111,"zchko access failed:",s,errno); X return(-1); X } else { X debug(F111,"zchko access ok:",s,x); X return(0); X } X} X X/* Z D E L E T -- Delete the named file. */ X Xzdelet(name) char *name; { X unlink(name); X} X X X/* Z R T O L -- Convert remote filename into local form */ X X/* For UNIX, this means changing uppercase letters to lowercase. */ X Xzrtol(name,name2) char *name, *name2; { X for ( ; *name != '\0'; name++) { X *name2++ = isupper(*name) ? tolower(*name) : *name; X } X *name2 = '\0'; X} X X X/* Z L T O R -- Convert filename from local format to common form. */ X Xzltor(name,name2) char *name, *name2; { X char work[100], *cp, *pp; X int dc = 0; X X strcpy(work,name); X for (cp = pp = work; *cp != '\0'; cp++) { /* strip path name */ X if (*cp == '/') { X pp = cp; X pp++; X } X else if (islower(*cp)) *cp = toupper(*cp); /* Uppercase letters */ X else if (*cp == '~') *cp = 'X'; /* Change tilde to 'X' */ X else if ((*cp == '.') && (++dc > 1)) *cp = 'X'; /* & extra dots */ X } X cp = name2; /* If nothing before dot, */ X if (*pp == '.') *cp++ = 'X'; /* insert 'X' */ X strcpy(cp,pp); X} X X X/* Z C H D I R -- Change directory */ X Xzchdir(dirnam) char *dirnam; { X char *hd; X if (*dirnam == '\0') hd = getenv("HOME"); X else hd = dirnam; X return((chdir(hd) == 0) ? 1 : 0); X} X X X/* Z H O M E -- Return pointer to user's home directory */ X Xchar * Xzhome() { X return(getenv("HOME")); X} X X/* Z X C M D -- Run a system command so its output can be read like a file */ X Xzxcmd(comand) char *comand; { X int pipes[2]; X if (pipe(pipes) != 0) return(0); /* can't make pipe, fail */ X if ((pid = fork()) == 0) { /* child */ X X/*#if BSD4*/ /* Code from Dave Tweten@AMES-NASA */ X /* readapted to use getpwuid to find login shell */ X /* -- H. Fischer */ X char *shpath, *shname, *shptr; /* to find desired shell */ X struct passwd *p; X extern struct passwd * getpwuid(); X extern int getuid(); X char *defShel = "/bin/sh"; /* default shell */ X/*#endif*/ X X close(pipes[0]); /* close input side of pipe */ X close(0); /* close stdin */ X if (open("/dev/null",0) < 0) return(0); /* replace input by null */ X X#ifndef UXIII X dup2(pipes[1],1); /* replace stdout & stderr */ X dup2(pipes[1],2); /* by the pipe */ X#else X close(1); /* simulate dup2 */ X if (dup(pipes[1]) != 1 ) X conol("trouble duping stdout in routine zxcmd\n"); X close(2); /* simulate dup2 */ X if (dup(pipes[1]) != 2 ) X conol("trouble duping stderr in routine zxcmd\n"); X#endif X X close(pipes[1]); /* get rid of this copy of the pipe */ X X/**** shptr = shname = shpath = getenv("SHELL"); /* What shell? */ X p = getpwuid( getuid() ); /* get login data */ X if ( p == (struct passwd *) NULL || !*(p->pw_shell) ) shpath = defShel; X else shpath = p->pw_shell; X shptr = shname = shpath; X while (*shptr != '\0') if (*shptr++ == '/') shname = shptr; X execl(shpath,shname,"-c",comand,0); /* Execute the command */ X X/**** execl("/bin/sh","sh","-c",comand,0); /* Execute the command */ X X exit(0); } /* just punt if it didn't work */ X X close(pipes[1]); /* don't need the output side */ X fp[ZIFILE] = fdopen(pipes[0],"r"); /* open a stream for it */ X return(1); X} X X/* Z C L O S F - wait for the child fork to terminate and close the pipe. */ X Xzclosf() { X int wstat; X fclose(fp[ZIFILE]); X fp[ZIFILE] = NULL; X while ((wstat = wait(0)) != pid && wstat != -1) ; X} X X/* Z X P A N D -- Expand a wildcard string into an array of strings */ X/* X Returns the number of files that match fn1, with data structures set up X so that first file (if any) will be returned by the next znext() call. X*/ Xzxpand(fn) char *fn; { X fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ X if (fcount > 0) { X mtchptr = mtchs; /* Save pointer for next. */ X } X debug(F111,"zxpand",mtchs[0],fcount); X return(fcount); X} X X X/* Z N E X T -- Get name of next file from list created by zxpand(). */ X/* X Returns >0 if there's another file, with its name copied into the arg string, X or 0 if no more files in list. X*/ Xznext(fn) char *fn; { X if (fcount-- > 0) strcpy(fn,*mtchptr++); X else *fn = '\0'; X debug(F111,"znext",fn,fcount+1); X return(fcount+1); X} X X X/* Z N E W N -- Make a new name for the given file */ X Xznewn(fn,s) char *fn, **s; { X static char buf[100]; X char *bp, *xp; X int len = 0, n = 0, d = 0, t; X X bp = buf; X while (*fn) { X *bp++ = *fn++; X len++; X } X *bp++ = '*'; /* Put a star on the end */ X *bp-- = '\0'; X X n = zxpand(buf); /* Expand the resulting wild name */ X X while (n-- > 0) { /* Find any existing name~d files */ X xp = *mtchptr++; X xp += len; X if (*xp == '~') { X t = atoi(xp+1); X if (t > d) d = t; /* Get maximum d */ X } X } X sprintf(bp,"~%d",d+1); /* Make and return name~(d+1) */ X *s = buf; X} X X/* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */ X X/* X * The path structure is used to represent the name to match. X * Each slash-separated segment of the name is kept in one X * such structure, and they are linked together, to make X * traversing the name easier. X */ X Xstruct path { X char npart[MAXNAMLEN]; /* name part of path segment */ X struct path *fwd; /* forward ptr */ X }; X X#define SSPACE 2000 /* size of string-generating buffer */ Xstatic char sspace[SSPACE]; /* buffer to generate names in */ Xstatic char *freeptr,**resptr; /* copies of caller's arguments */ Xstatic int remlen; /* remaining length in caller's array*/ Xstatic int numfnd; /* number of matches found */ X X/* X * splitpath: X * takes a string and splits the slash-separated portions into X * a list of path structures. Returns the head of the list. The X * structures are allocated by malloc, so they must be freed. X * Splitpath is used internally by the filename generator. X * X * Input: A string. X * Returns: A linked list of the slash-separated segments of the input. X */ X Xstruct path * Xsplitpath(p) Xchar *p; X{ X struct path *head,*cur,*prv; X int i; X head = prv = NULL; X if (*p == '/') p++; /* skip leading slash */ X while (*p != '\0') X { X cur = (struct path *) malloc(sizeof (struct path)); X cur -> fwd = NULL; X if (head == NULL) head = cur; X else prv -> fwd = cur; /* link into chain */ X prv = cur; X for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++) X cur -> npart[i] = *p++; X cur -> npart[i] = '\0'; /* end this segment */ X if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++; X if (*p == '/') p++; X } X return(head); X} X X/* X * fgen: X * This is the actual name generator. It is passed a string, X * possibly containing wildcards, and an array of character pointers. X * It finds all the matching filenames and stores them into the array. X * The returned strings are allocated from a static buffer local to X * this module (so the caller doesn't have to worry about deallocating X * them); this means that successive calls to fgen will wipe out X * the results of previous calls. This isn't a problem here X * because we process one wildcard string at a time. X * X * Input: a wildcard string, an array to write names to, the X * length of the array. X * Returns: the number of matches. The array is filled with filenames X * that matched the pattern. If there wasn't enough room in the X * array, -1 is returned. X * By: Jeff Damens, CUCCA, 1984. X */ X Xfgen(pat,resarry,len) Xchar *pat,*resarry[]; Xint len; X{ X struct path *head; X char scratch[100],*sptr; X head = splitpath(pat); X if (*pat == '/') X { X scratch[0] = '/'; X sptr = scratch+1; X } X else X { X strcpy(scratch,"./"); X sptr = scratch+2; X } /* init buffer correctly */ X numfnd = 0; /* none found yet */ X freeptr = sspace; /* this is where matches are copied */ X resptr = resarry; /* static copies of these so*/ X remlen = len; /* recursive calls can alter them */ X traverse(head,scratch,sptr); /* go walk the directory tree */ X for (; head != NULL; head = head -> fwd) X free(head); /* return the path segments */ X return(numfnd); /* and return the number of matches */ X} X X/* traverse: X * Walks the directory tree looking for matches to its arguments. X * The algorithm is, briefly: X * If the current pattern segment contains no wildcards, that X * segment is added to what we already have. If the name so far X * exists, we call ourselves recursively with the next segment X * in the pattern string; otherwise, we just return. X * X * If the current pattern segment contains wildcards, we open the name X * we've accumulated so far (assuming it is really a directory), then read X * each filename in it, and, if it matches the wildcard pattern segment, add X * that filename to what we have so far and call ourselves recursively on the X * next segment. X * X * Finally, when no more pattern segments remain, we add what's accumulated X * so far to the result array and increment the number of matches. X * X * Input: a pattern path list (as generated by splitpath), a string X * pointer that points to what we've traversed so far (this X * can be initialized to "/" to start the search at the root X * directory, or to "./" to start the search at the current X * directory), and a string pointer to the end of the string X * in the previous argument. X * Returns: nothing. X */ Xtraverse(pl,sofar,endcur) Xstruct path *pl; Xchar *sofar,*endcur; X{ X#ifdef BSD4 X DIR *fd; X struct direct *dirbuf; X#else X int fd; X struct direct dir_entry; X struct direct *dirbuf = &dir_entry; X#endif X struct stat statbuf; X if (pl == NULL) X { X *--endcur = '\0'; /* end string, overwrite trailing / */ X addresult(sofar); X return; X } X if (!iswild(pl -> npart)) X { X strcpy(endcur,pl -> npart); X endcur += strlen(pl -> npart); X *endcur = '\0'; /* end current string */ X if (stat(sofar,&statbuf) == 0) /* if current piece exists */ X { X *endcur++ = '/'; /* add slash to end */ X *endcur = '\0'; /* and end the string */ X traverse(pl -> fwd,sofar,endcur); X } X return; X } X/* cont'd... */ X X/*...traverse, cont'd */ X X/* segment contains wildcards, have to search directory */ X *endcur = '\0'; /* end current string */ X if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */ X if ((statbuf.st_mode & S_IFDIR) == 0) return; /* not a directory, skip */ X#ifdef BSD4 X if ((fd = opendir(sofar)) == NULL) return; /* can't open, forget it */ X while (dirbuf = readdir(fd)) X#else X if ((fd = open(sofar,O_RDONLY)) < 0) return; /* can't open, forget it */ X while ( read(fd,dirbuf,sizeof dir_entry) ) X#endif X if (dirbuf->d_ino != 0 && match(pl -> npart,dirbuf->d_name)) { X char *eos; X strcpy(endcur,dirbuf->d_name); X eos = endcur + strlen(dirbuf->d_name); X *eos = '/'; /* end this segment */ X traverse(pl -> fwd,sofar,eos+1); X } X#ifdef BSD4 X closedir(fd); X#else X close(fd); X#endif X} X X/* X * addresult: X * Adds a result string to the result array. Increments the number X * of matches found, copies the found string into our string X * buffer, and puts a pointer to the buffer into the caller's result X * array. Our free buffer pointer is updated. If there is no X * more room in the caller's array, the number of matches is set to -1. X * Input: a result string. X * Returns: nothing. X */ X Xaddresult(str) Xchar *str; X{ X int l; X if (strncmp(str,"./",2) == 0) str += 2; X if (--remlen < 0) { X numfnd = -1; X return; X } X l = strlen(str) + 1; /* size this will take up */ X if ((freeptr + l) > &sspace[SSPACE]) { X numfnd = -1; /* do not record if not enough space */ X return; X } X strcpy(freeptr,str); X *resptr++ = freeptr; X freeptr += l; X numfnd++; X} X Xiswild(str) Xchar *str; X{ X char c; X while ((c = *str++) != '\0') X if (c == '*' || c == '?') return(1); X return(0); X} X X/* X * match: X * pattern matcher. Takes a string and a pattern possibly containing X * the wildcard characters '*' and '?'. Returns true if the pattern X * matches the string, false otherwise. X * by: Jeff Damens, CUCCA X * X * Input: a string and a wildcard pattern. X * Returns: 1 if match, 0 if no match. X */ X Xmatch(pattern,string) char *pattern,*string; { X char *psave,*ssave; /* back up pointers for failure */ X psave = ssave = NULL; X while (1) { X for (; *pattern == *string; pattern++,string++) /* skip first */ X if (*string == '\0') return(1); /* end of strings, succeed */ X if (*string != '\0' && *pattern == '?') { X pattern++; /* '?', let it match */ X string++; X } else if (*pattern == '*') { /* '*' ... */ X psave = ++pattern; /* remember where we saw it */ X ssave = string; /* let it match 0 chars */ X } else if (ssave != NULL && *ssave != '\0') { /* if not at end */ X /* ...have seen a star */ X string = ++ssave; /* skip 1 char from string */ X pattern = psave; /* and back up pattern */ X } else return(0); /* otherwise just fail */ X } X} !FUNKY!STUFF!
gregg@okstate.UUCP (03/08/85)
echo x - ckcmd.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckcmd.c Xchar *cmdv = "Unix cmd package V1.0(015) 27 Feb 85"; X X/* C K C M D -- Interactive command package for Unix */ X/* X Modelled after the DECSYSTEM-20 command parser (the COMND JSYS) X X Features: X . parses and verifies keywords, text strings, numbers, and other data X . displays appropriate menu or help message when user types "?" X . does keyword and filename completion when user types ESC X . accepts any unique abbreviation for a keyword X . allows keywords to have attributes, like "invisible" X . can supply defaults for fields omitted by user X . provides command line editing (character, word, and line deletion) X . accepts input from keyboard, command files, or redirected stdin X . allows for full or half duplex operation, character or line input X . settable prompt, protected from deletion X X Functions: X cmsetp - Set prompt X cmsavp - Save current prompt X prompt - Issue prompt X cmini - Clear the command buffer (before parsing a new command) X cmres - Reset command buffer pointers (before reparsing) X cmkey - Parse a keyword X cmnum - Parse a number X cmifi - Parse an input file name X cmofi - Parse an output file name X cmfld - Parse an arbitrary field X cmtxt - Parse a text string X cmcfm - Parse command confirmation (end of line) X stripq - Strip out backslash quotes from a string. X X Return codes: X -3: no input provided when required X -2: input was invalid X -1: reparse required (user deleted into a preceding field) X 0 or greater: success X See individual functions for greater detail. X X Before using these routines, the caller should #include ckcmd.h, and X set the program's prompt by calling cmsetp(). If the file parsing X functions cmifi and cmofi are to be used, this module must be linked X with a ckz??? file system support module for the appropriate system, X e.g. ckzbsd for Berkeley Unix. If the caller puts the terminal in X character wakeup ("cbreak") mode with no echo, then these functions will X provide line editing -- character, word, and line deletion, as well as X keyword and filename completion upon ESC and help strings, keyword, or X file menus upon '?'. If the caller puts the terminal into character X wakeup/noecho mode, care should be taken to restore it before exit from X or interruption of the program. If the character wakeup mode is not X set, the system's own line editor may be used. X X Author: Frank da Cruz (SY.FDC@CU20B), X Columbia University Center for Computing Activities, Jan 1985. X Copyright (C) 1985, Trustees of Columbia University in the City of New York. X Permission is granted to any individual or institution to copy or use this X software except for explicitly commercial purposes, provided this copyright X notice is retained. X*/ X X/* Includes */ X X#include <stdio.h> /* Standard C I/O package */ X#include <ctype.h> /* Character types */ X#include "ckcmd.h" /* Command parsing definitions */ X#include "ckdebu.h" /* Formats for debug() */ X X/* Local variables */ X Xint psetf = 0, /* Flag that prompt has been set */ X cc = 0, /* Character count */ X dpx = 0; /* Duplex (0 = full) */ X Xint hw = HLPLW, /* Help line width */ X hc = HLPCW, /* Help line column width */ X hh, /* Current help column number */ X hx; /* Current help line position */ X X#define PROML 60 /* Maximum length for prompt */ X Xchar cmprom[PROML+1]; /* Program's prompt */ Xchar *dfprom = "Command? "; /* Default prompt */ X Xint cmflgs; /* Command flags */ X Xchar cmdbuf[CMDBL+4]; /* Command buffer */ Xchar hlpbuf[HLPBL+4]; /* Help string buffer */ Xchar atmbuf[ATMBL+4]; /* Atom buffer */ Xchar filbuf[ATMBL+4]; /* File name buffer */ X X/* Command buffer pointers */ X Xstatic char *bp, /* Current command buffer position */ X *pp, /* Start of current field */ X *np; /* Start of next field */ X X/* C M S E T P -- Set the program prompt. */ X Xcmsetp(s) char *s; { X char *strncpy(); X psetf = 1; /* Flag that prompt has been set. */ X strncpy(cmprom,s,PROML - 1); /* Copy the string. */ X cmprom[PROML] = NUL; X} X X X/* C M S A V P -- Save a copy of the current prompt. */ X Xcmsavp(s,n) int n; char s[]; { X strncpy(s,cmprom,n-1); X s[n] = NUL; X} X X X/* P R O M P T -- Issue the program prompt. */ X Xprompt() { X if (psetf == 0) cmsetp(dfprom); /* If no prompt set, set default. */ X printf("\r%s",cmprom); /* Print the prompt. */ X} X X X/* C M R E S -- Reset pointers to beginning of command buffer. */ X Xcmres() { X cc = 0; /* Reset character counter. */ X pp = np = bp = cmdbuf; /* Point to command buffer. */ X cmflgs = -5; /* Parse not yet started. */ X} X X X/* C M I N I -- Clear the command and atom buffers, reset pointers. */ X X/* XThe argument specifies who is to echo the user's typein -- X 1 means the cmd package echoes X 0 somebody else (system, front end, terminal) echoes X*/ Xcmini(d) int d; { X for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL; X *atmbuf = NUL; X dpx = d; X cmres(); X} X Xstripq(s) char *s; { /* Function to strip '\' quotes */ X char *t; X while (*s) { X if (*s == '\\') { X for (t = s; *t != '\0'; t++) *t = *(t+1); X } X s++; X } X} X X/* C M N U M -- Parse a number in the indicated radix */ X X/* For now, only works for positive numbers in base 10. */ X X/* X Returns X -3 if no input present when required, X -2 if user typed an illegal number, X -1 if reparse needed, X 0 otherwise, with n set to number that was parsed X*/ Xcmnum(xhlp,xdef,radix,n) char *xhlp, *xdef; int radix, *n; { X int x; char *s; X X if (radix != 10) { /* Just do base 10 for now */ X printf("cmnum: illegal radix - %d\n",radix); X return(-1); X } X X x = cmfld(xhlp,xdef,&s); X debug(F101,"cmnum: cmfld","",x); X if (x < 0) return(x); /* Parse a field */ X X if (digits(atmbuf)) { /* Convert to number */ X *n = atoi(atmbuf); X return(x); X } else { X printf("\n?not a number - %s\n",s); X return(-2); X } X} X X/* C M O F I -- Parse the name of an output file */ X X/* X Depends on the external function zchko(); if zchko() not available, use X cmfld() to parse output file names. X X Returns X -3 if no input present when required, X -2 if permission would be denied to create the file, X -1 if reparse needed, X 0 or 1 otherwise, with xp pointing to name. X*/ Xcmofi(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { X int x; char *s; X X if (*xhlp == NUL) xhlp = "Output file"; X *xp = ""; X X if ((x = cmfld(xhlp,xdef,&s)) < 0) return(x); X X if (chkwld(s)) { X printf("\n?Wildcards not allowed - %s\n",s); X return(-2); X } X if (zchko(s) < 0) { X printf("\n?Write permission denied - %s\n",s); X return(-2); X } else { X *xp = s; X return(x); X } X} X X/* C M I F I -- Parse the name of an existing file */ X X/* X This function depends on the external functions: X zchki() - Check if input file exists and is readable. X zxpand() - Expand a wild file specification into a list. X znext() - Return next file name from list. X If these functions aren't available, then use cmfld() to parse filenames. X*/ X/* X Returns X -4 EOF X -3 if no input present when required, X -2 if file does not exist or is not readable, X -1 if reparse needed, X 0 or 1 otherwise, with: X xp pointing to name, X wild = 1 if name contains '*' or '?', 0 otherwise. X*/ Xcmifi(xhlp,xdef,xp,wild) char *xhlp, *xdef, **xp; int *wild; { X int i, x, xc, y; char *sp; X X cc = xc = 0; /* Initialize counts & pointers */ X *xp = ""; X if ((x = cmflgs) != 1) { /* Already confirmed? */ X x = getwd(); /* No, get a word */ X } else { X cc = setatm(xdef); /* If so, use default, if any. */ X } X *xp = atmbuf; /* Point to result. */ X *wild = chkwld(*xp); X X while (1) { X xc += cc; /* Count the characters. */ X debug(F111,"cmifi: getwd",atmbuf,xc); X switch (x) { X case -4: /* EOF */ X case -2: /* Out of space. */ X case -1: /* Reparse needed */ X return(x); X X/* cont'd... */ X X/* ...cmifi(), cont'd */ X X X case 0: /* SP or NL */ X case 1: X if (xc == 0) *xp = xdef; /* If no input, return default. */ X else *xp = atmbuf; X if (**xp == NUL) return(-3); /* If field empty, return -3. */ X X /* If filespec is wild, see if there are any matches */ X X *wild = chkwld(*xp); X debug(F101," *wild","",*wild); X if (*wild != 0) { X y = zxpand(*xp); X if (y == 0) { X printf("\n?No files match - %s\n",*xp); X return(-2); X } else if (y < 0) { X printf("\n?Too many files match - %s\n",*xp); X return(-2); X } else return(x); X } X X /* If not wild, see if it exists and is readable. */ X X y = zchki(*xp); X if (y == -3) { X printf("\n?Read permission denied - %s\n",*xp); X return(-2); X } else if (y == -2) { X printf("\n?File not readable - %s\n",*xp); X return(-2); X } else if (y < 0) { X printf("\n?File not found - %s\n",*xp); X return(-2); X } X return(x); X/* cont'd... */ X X/* ...cmifi(), cont'd */ X X X case 2: /* ESC */ X if (xc == 0) { X if (*xdef != '\0') { X printf("%s ",xdef); /* If at beginning of field, */ X addbuf(xdef); /* supply default. */ X cc = setatm(xdef); X } else { /* No default */ X putchar(BEL); X } X break; X } X if (*wild = chkwld(*xp)) { /* No completion if wild */ X putchar(BEL); X break; X } X sp = atmbuf + cc; X *sp++ = '*'; X *sp-- = '\0'; X y = zxpand(atmbuf); /* Add * and expand list. */ X *sp = '\0'; /* Remove *. */ X X if (y == 0) { X printf("\n?No files match - %s\n",atmbuf); X return(-2); X } else if (y < 0) { X printf("\n?Too many files match - %s\n",atmbuf); X return(-2); X } else if (y > 1) { /* Not unique, just beep. */ X putchar(BEL); X } else { /* Unique, complete it. */ X znext(filbuf); /* Get whole name of file. */ X sp = filbuf + cc; /* Point past what user typed. */ X printf("%s ",sp); /* Complete the name. */ X addbuf(sp); /* Add the characters to cmdbuf. */ X setatm(pp); /* And to atmbuf. */ X *xp = atmbuf; /* Return pointer to atmbuf. */ X return(cmflgs = 0); X } X break; X X/* cont'd... */ X X/* ...cmifi(), cont'd */ X X X case 3: /* Question mark */ X if (*xhlp == NUL) X printf(" Input file specification"); X else X printf(" %s",xhlp); X if (xc > 0) { X sp = atmbuf + cc; /* Insert * at end */ X *sp++ = '*'; X *sp-- = '\0'; X y = zxpand(atmbuf); X *sp = '\0'; X if (y == 0) { X printf("\n?No files match - %s\n",atmbuf); X return(-2); X } else if (y < 0) { X printf("\n?Too many file match - %s\n",atmbuf); X return(-2); X } else { X printf(", one of the following:\n"); X clrhlp(); X for (i = 0; i < y; i++) { X znext(filbuf); X addhlp(filbuf); X } X dmphlp(); X } X } else printf("\n"); X printf("%s%s",cmprom,cmdbuf); X break; X } X x = getwd(); X } X} X X X X/* C H K W L D -- Check for wildcard characters '*' or '?' */ X Xchkwld(s) char *s; { X X for ( ; *s != '\0'; s++) { X if ((*s == '*') || (*s == '?')) X return(1); X } X return(0); X} X X/* C M F L D -- Parse an arbitrary field */ X/* X Returns X -3 if no input present when required, X -2 if field too big for buffer, X -1 if reparse needed, X 0 otherwise, xp pointing to string result. X*/ Xcmfld(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { X int x, xc; X X cc = xc = 0; /* Initialize counts & pointers */ X *xp = ""; X if ((x = cmflgs) != 1) { /* Already confirmed? */ X x = getwd(); /* No, get a word */ X } else { X cc = setatm(xdef); /* If so, use default, if any. */ X } X *xp = atmbuf; /* Point to result. */ X X while (1) { X xc += cc; /* Count the characters. */ X debug(F111,"cmfld: getwd",atmbuf,xc); X debug(F101," x","",x); X switch (x) { X case -4: /* EOF */ X case -2: /* Out of space. */ X case -1: /* Reparse needed */ X return(x); X case 0: /* SP or NL */ X case 1: X if (xc == 0) *xp = xdef; /* If no input, return default. */ X else *xp = atmbuf; X if (**xp == NUL) x = -3; /* If field empty, return -3. */ X return(x); X case 2: /* ESC *** (maybe treat as SP) */ X if (xc == 0) { X printf("%s ",xdef); /* If at beginning of field, */ X addbuf(xdef); /* supply default. */ X cc = setatm(xdef); X } else { X putchar(BEL); /* Beep if already into field. */ X } X break; X case 3: /* Question mark */ X if (*xhlp == NUL) X printf(" Please complete this field"); X else X printf(" %s",xhlp); X printf("\n%s%s",cmprom,cmdbuf); X break; X } X x = getwd(); X } X} X X/* C M T X T -- Get a text string, including confirmation */ X X/* X Print help message 'xhlp' if ? typed, supply default 'xdef' if null X string typed. Returns X X -1 if reparse needed or buffer overflows. X 1 otherwise. X X with cmflgs set to return code, and xp pointing to result string. X*/ X Xcmtxt(xhlp,xdef,xp) char *xhlp; char *xdef; char **xp; { X X int x, xc; X X cc = xc = 0; /* Start counters off at 0 */ X *xp = ""; /* And pointer to null string. */ X *atmbuf = NUL; /* And empty atom buffer. */ X if ((x = cmflgs) != 1) { X x = getwd(); /* Get first word. */ X *xp = pp; /* Save pointer to it. */ X } X while (1) { X xc += cc; /* Accumulate count. */ X debug(F111,"cmtxt: getwd",atmbuf,xc); X switch (x) { X case -4: /* EOF */ X case -2: /* Overflow */ X case -1: /* Deletion */ X return(x); X case 0: /* Space */ X break; X case 1: /* CR or LF */ X if (xc == 0) *xp = xdef; X return(x); X case 2: /* ESC */ X if (xc == 0) { X printf("%s ",xdef); X cc = addbuf(xdef); X } else { X putchar(BEL); X } X break; X case 3: /* Question Mark */ X if (*xhlp == NUL) X printf(" Text string"); X else X printf(" %s",xhlp); X printf("\n%s%s",cmprom,cmdbuf); X break; X default: X printf("\n?Unexpected return code from getwd() - %d\n",x); X return(-2); X } X x = getwd(); X } X} X X/* C M K E Y -- Parse a keyword */ X X/* X Call with: X table -- keyword table, in 'struct keytab' format; X n -- number of entries in table; X xhlp -- pointer to help string; X xdef -- pointer to default keyword; X X Returns: X -3 -- no input supplied and no default available X -2 -- input doesn't uniquely match a keyword in the table X -1 -- user deleted too much, command reparse required X n >= 0 -- value associated with keyword X*/ X Xcmkey(table,n,xhlp,xdef) struct keytab table[]; int n; char *xhlp, *xdef; { X int i, y, z, zz, xc; X char *xp; X X xc = cc = 0; /* Clear character counters. */ X X if ((zz = cmflgs) == 1) /* Command already entered? */ X setatm(xdef); X else zz = getwd(); X Xdebug(F101,"cmkey: table length","",n); Xdebug(F101," cmflgs","",cmflgs); Xdebug(F101," zz","",zz); Xwhile (1) { X xc += cc; X debug(F111,"cmkey: getwd",atmbuf,xc); X X switch(zz) { X case -4: /* EOF */ X case -2: /* Buffer overflow */ X case -1: /* Or user did some deleting. */ X return(zz); X X case 0: /* User terminated word with space */ X case 1: /* or newline */ X if (cc == 0) setatm(xdef); X y = lookup(table,atmbuf,n,&z); X switch (y) { X case -2: X printf("\n?Ambiguous - %s\n",atmbuf); X return(cmflgs = -2); X case -1: X printf("\n?Invalid - %s\n",atmbuf); X return(cmflgs = -2); X default: X break; X } X return(y); X X/* cont'd... */ X X/* ...cmkey(), cont'd */ X X case 2: /* User terminated word with ESC */ X if (cc == 0) { X if (*xdef != NUL) { /* Nothing in atmbuf */ X printf("%s ",xdef); /* Supply default if any */ X addbuf(xdef); X cc = setatm(xdef); X debug(F111,"cmkey: default",atmbuf,cc); X } else { X putchar(BEL); /* No default, just beep */ X break; X } X } X y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */ X debug(F111,"cmkey: esc",atmbuf,y); X if (y == -2) { X putchar(BEL); X break; X } X if (y == -1) { X printf("\n?Invalid - %s\n",atmbuf); X return(cmflgs = -2); X } X xp = table[z].kwd + cc; X printf("%s ",xp); X addbuf(xp); X debug(F110,"cmkey: addbuf",cmdbuf,0); X return(y); X X/* cont'd... */ X X/* ...cmkey(), cont'd */ X X case 3: /* User terminated word with "?" */ X y = lookup(table,atmbuf,n,&z); X if (y > -1) { X printf(" %s\n%s%s",table[z].kwd,cmprom,cmdbuf); X break; X } else if (y == -1) { X printf("\n?Invalid\n"); X return(cmflgs = -2); X } X X if (*xhlp == NUL) X printf(" One of the following:\n"); X else X printf(" %s, one of the following:\n",xhlp); X X clrhlp(); X for (i = 0; i < n; i++) { X if (!strncmp(table[i].kwd,atmbuf,cc) X && !test(table[i].flgs,CM_INV)) X addhlp(table[i].kwd); X } X dmphlp(); X printf("%s%s", cmprom, cmdbuf); X break; X X default: X printf("\n%d - Unexpected return code from getwd\n",zz); X return(cmflgs = -2); X } X zz = getwd(); X } X} X X/* C M C F M -- Parse command confirmation (end of line) */ X X/* X Returns X -2: User typed anything but whitespace or newline X -1: Reparse needed X 0: Confirmation was received X*/ X Xcmcfm() { X int x, xc; X X debug(F101,"cmcfm: cmflgs","",cmflgs); X X xc = cc = 0; X if (cmflgs == 1) return(0); X X while (1) { X x = getwd(); X xc += cc; X debug(F111,"cmcfm: getwd",atmbuf,xc); X switch (x) { X case -4: /* EOF */ X case -2: X case -1: X return(x); X X case 0: /* Space */ X continue; X case 1: /* End of line */ X if (xc > 0) { X printf("?Not confirmed - %s\n",atmbuf); X return(-2); X } else return(0); X case 2: X putchar(BEL); X continue; X X case 3: X if (xc > 0) { X printf("\n?Not confirmed - %s\n",atmbuf); X return(-2); X } X printf("\n Type a carriage return to confirm the command\n"); X printf("%s%s",cmprom,cmdbuf); X continue; X } X } X} X X/* Keyword help routines */ X X X/* C L R H L P -- Initialize/Clear the help line buffer */ X Xclrhlp() { /* Clear the help buffer */ X hlpbuf[0] = NUL; X hh = hx = 0; X} X X X/* A D D H L P -- Add a string to the help line buffer */ X Xaddhlp(s) char *s; { /* Add a word to the help buffer */ X int j; X X hh++; /* Count this column */ X X for (j = 0; j < hc; j++) { /* Fill the column */ X if (*s != NUL) /* First with chars from the string */ X hlpbuf[hx++] = *s++; X else { X if (hh < (hw / hc)) /* Then with spaces */ X hlpbuf[hx++] = SP; X else { X hlpbuf[hx++] = NUL; /* If last column, no spaces. */ X dmphlp(); /* Print it. */ X return; X } X } X } X if (*s != NUL) /* Still some chars left in string? */ X hlpbuf[hx-1] = '+'; /* Mark as too long for column. */ X} X X X/* D M P H L P -- Dump the help line buffer */ X Xdmphlp() { /* Print the help buffer */ X hlpbuf[hx++] = NUL; X printf(" %s\n",hlpbuf); X clrhlp(); X} X X/* L O O K U P -- Lookup the string in the given array of strings */ X X/* X Call this way: v = lookup(table,word,n,&x); X X table - a 'struct keytab' table. X word - the target string to look up in the table. X n - the number of elements in the table. X x - address of an integer for returning the table array index. X X The keyword table must be arranged in ascending alphabetical order, and X all letters must be lowercase. X X Returns the keyword's associated value ( zero or greater ) if found, X with the variable x set to the array index, or: X X -3 if nothing to look up (target was null), X -2 if ambiguous, X -1 if not found. X X A match is successful if the target matches a keyword exactly, or if X the target is a prefix of exactly one keyword. It is ambiguous if the X target matches two or more keywords from the table. X*/ X Xlookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; { X X int i, v, cmdlen; X X/* Lowercase & get length of target, if it's null return code -3. */ X X if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3); X X/* Not null, look it up */ X X for (i = 0; i < n-1; i++) { X if (!strcmp(table[i].kwd,cmd) || X ((v = !strncmp(table[i].kwd,cmd,cmdlen)) && X strncmp(table[i+1].kwd,cmd,cmdlen))) { X *x = i; X return(table[i].val); X } X if (v) return(-2); X } X X/* Last (or only) element */ X X if (!strncmp(table[n-1].kwd,cmd,cmdlen)) { X *x = n-1; X return(table[n-1].val); X } else return(-1); X} X X/* G E T W D -- Gets a "word" from the command input stream */ X X/* XUsage: retcode = getwd(); X XReturns: X -4 if end of file (e.g. pipe broken) X -2 if command buffer overflows X -1 if user did some deleting X 0 if word terminates with SP or tab X 1 if ... CR X 2 if ... ESC X 3 if ... ? X XWith: X pp pointing to beginning of word in buffer X bp pointing to after current position X atmbuf containing a copy of the word X cc containing the number of characters in the word copied to atmbuf X*/ Xgetwd() { X X int c; /* Current char */ X static int inword = 0; /* Flag for start of word found */ X int quote = 0; /* Flag for quote character */ X int echof = 0; /* Flag for whether to echo */ X int ignore = 0; X X pp = np; /* Start of current field */ X debug(F101,"getwd: cmdbuf","",(int) cmdbuf); X debug(F101," bp","",(int) bp); X debug(F101," pp","",(int) pp); X debug(F110," cmdbuf",cmdbuf,0); X X while (bp < cmdbuf+CMDBL) { /* Loop */ X X ignore = echof = 0; /* Flag for whether to echo */ X X if ((c = *bp) == NUL) { /* Get next character */ X if (dpx) echof = 1; /* from reparse buffer */ X c = getchar(); /* or from tty. */ X if (c == EOF) return(-4); X } else ignore = 1; X X if (quote == 0) { X X if (!ignore && (c == '\\')) { /* Quote character */ X quote = 1; X continue; X } X if (c == FF) { /* Formfeed. */ X c = NL; /* Replace with newline */ X system("clear"); /* and clear the screen. */ X } X X if (c == HT) c = SP; /* Substitute space for tab. */ X X/* cont'd... */ X X/* ...getwd(), cont'd */ X X if (c == SP) { /* If space */ X *bp++ = c; /* deposit it in buffer. */ X if (echof) putchar(c); /* echo it. */ X if (inword == 0) { /* If leading, gobble it. */ X pp++; X continue; X } else { /* If terminating, return. */ X np = bp; X setatm(pp); X inword = 0; X return(cmflgs = 0); X } X } X if (c == NL) { /* CR, LF */ X *bp = NUL; /* End the string */ X if (echof) putchar(c); /* Echo the typein */ X np = bp; /* Where to start next field. */ X setatm(pp); /* Copy this field to atom buffer. */ X inword = 0; X return(cmflgs = 1); X } X if (!ignore && (c == '?')) { /* Question mark */ X putchar(c); X *bp = NUL; X setatm(pp); X return(cmflgs = 3); X } X if (c == ESC) { /* ESC */ X *bp = NUL; X setatm(pp); X return(cmflgs = 2); X } X if (c == BS || c == RUB) { /* Character deletion */ X if (bp > cmdbuf) { /* If still in buffer... */ X printf("\b \b"); /* erase character from screen, */ X bp--; /* point behind it, */ X if (*bp == SP) inword = 0; /* Flag if current field gone */ X *bp = NUL; /* Erase character from buffer. */ X } else { /* Otherwise, */ X putchar(BEL); /* beep, */ X cmres(); /* and start parsing a new command. */ X } X if (pp < bp) continue; X else return(cmflgs = -1); X } X if (c == LDEL) { /* ^U, line deletion */ X while ((bp--) > cmdbuf) { X printf("\b \b"); X *bp = NUL; X } X cmres(); /* Restart the command. */ X inword = 0; X return(cmflgs = -2); X } X X/* cont'd... */ X X/* ...getwd(), cont'd */ X X if (c == WDEL) { /* ^W, word deletion */ X if (bp <= cmdbuf) { /* Beep if nothing to delete */ X putchar(BEL); X cmres(); X return(cmflgs = -1); X } X bp--; X for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) { X printf("\b \b"); X *bp = NUL; X } X for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) { X printf("\b \b"); X *bp = NUL; X } X *bp++ == NUL; X inword = 0; X return(cmflgs = -1); X } X if (c == RDIS) { /* ^R, redisplay */ X *bp = NUL; X printf("\n%s%s",cmprom,cmdbuf); X continue; X } X } X if (echof) putchar(c); /* If tty input, echo. */ X inword = 1; /* Flag we're in a word. */ X quote = 0; /* Turn off quote. */ X *bp++ = c; /* And deposit it. */ X } /* end of big while */ X putchar(BEL); /* Get here if... */ X printf("\n?Buffer full\n"); X return(cmflgs = -2); X} X X/* Utility functions */ X X/* A D D B U F -- Add the string pointed to by cp to the command buffer */ X Xaddbuf(cp) char *cp; { X int len = 0; X while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) { X *bp++ = *cp++; /* Copy and */ X len++; /* count the characters. */ X } X *bp++ = SP; /* Put a space at the end */ X *bp = NUL; /* Terminate with a null */ X np = bp; /* Update the next-field pointer */ X return(len); /* Return the length */ X} X X/* S E T A T M -- Deposit a string in the atom buffer */ X Xsetatm(cp) char *cp; { X char *ap; X cc = 0; X ap = atmbuf; X *ap = NUL; X while (*cp == SP) cp++; X while ((*cp != SP) && (*cp != NL) && (*cp != NUL)) { X *ap++ = *cp++; X cc++; X } X *ap++ = NUL; X return(cc); /* Return length */ X} X X/* D I G I T S -- Verify that all the characters in line are digits */ X Xdigits(s) char *s; { X while (*s) { X if (!isdigit(*s)) return(0); X s++; X } X return(1); X} X X/* L O W E R -- Lowercase a string */ X Xlower(s) char *s; { X int n = 0; X while (*s) { X if (isupper(*s)) *s = tolower(*s); X s++, n++; X } X return(n); X} X X/* T E S T -- Bit test */ X Xtest(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */ X return((x & m) ? 1 : 0); X} !FUNKY!STUFF! echo x - ckconu.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckconu.c Xchar *connv = "Connect Command for Unix, V4.2(006) 5 March 85"; X X/* C K C O N U -- Dumb terminal connection to remote system, for Unix */ X/* X This module should work under all versions of Unix. It calls externally X defined system-dependent functions for i/o, but depends upon the existence X of the fork() function. X X Enhanced by H. Fischer to detect when child process (modem reader) X reports that the communications line has been broken and hang up. X Also enhanced to allow escaping from connect state to command X interpreter, to allow sending/receiving without breaking connection. X*/ X X#include "ckermi.h" X#include <signal.h> X#include <setjmp.h> X X#ifndef SIGUSR1 X#define SIGUSR1 16 X#endif X Xextern int local, speed, escape, duplex, parity, flow, seslog, mdmtyp; Xextern char ttname[], sesfil[]; X Xint i, active; /* Variables global to this module */ Xchar *chstr(); X X#define LBUFL 100 /* Line buffer */ Xchar lbuf[LBUFL]; X X/* Connect state parent/child communication signal handlers */ X Xstatic jmp_buf env_con; /* Envir ptr for connect errors */ X Xstatic Xconn_int() { /* Modem read failure handler, */ X longjmp(env_con,1); /* notifies parent process to stop */ X} X X/* C O N E C T -- Perform terminal connection */ X Xconect() { X int pid, /* process id of child (modem reader) */ X parent_id, /* process id of parent (keyboard reader) */ X n; X int c; /* c is a character, but must be signed X integer to pass thru -1, which is the X modem disconnection signal, and is X different from the character 0377 */ X char errmsg[50], *erp; X X if (!local) { X printf("Sorry, you must 'set line' first\n"); X return(-2); X } X if (speed < 0) { X printf("Sorry, you must 'set speed' first\n"); X return(-2); X } X if ((escape < 0) || (escape > 0177)) { X printf("Your escape character is not ASCII - %d\n",escape); X return(-2); X } X if (ttopen(ttname,local,mdmtyp) < 0) { X erp = errmsg; X sprintf(erp,"Sorry, can't open %s",ttname); X perror(errmsg); X return(-2); X } X printf("Connecting thru %s, speed %d.\r\n",ttname,speed); X printf("The escape character is %s (%d).\r\n",chstr(escape),escape); X printf("Type the escape character followed by C to get back,\r\n"); X printf("or followed by ? to see other options.\r\n"); X if (seslog) printf("(Session logged to %s.)\r\n",sesfil); X X/* Condition console terminal and communication line */ X X if (conbin(escape) < 0) { X printf("Sorry, can't condition console terminal\n"); X return(-2); X } X if (ttvt(speed,flow) < 0) { X conres(); X printf("Sorry, Can't condition communication line\n"); X return(-2); X } X X/* cont'd... */ X X/* ...connect, cont'd */ X X X parent_id = getpid(); /* get parent id for signalling */ X pid = fork(); /* All ok, make a fork */ X if (pid) { X active = 1; /* This fork reads, sends keystrokes */ X if (!setjmp(env_con)) { /* comm error in child process */ X signal(SIGUSR1,conn_int); /* routine for child process exit */ X while (active) { X c = coninc(0) & 0177; X if (c == escape) { /* Look for escape char */ X c = coninc(0) & 0177; X doesc(c); X } else { /* Ordinary character */ X ttoc(dopar(c)); /* Send it out with desired parity */ X if (duplex) { /* Half duplex? */ X conoc(c); /* Yes, also echo it. */ X if (seslog) zchout(ZSFILE,c); /* And maybe log it. */ X } X } X } X } /* come here on death of child */ X kill(pid,9); /* Done, kill inferior. */ X wait(0); /* Wait till gone. */ X conres(); /* Reset the console. */ X printf("C-Kermit Disconnected\n"); X return(0); X X } else { /* Inferior reads, prints port input */ X X while (1) { /* Fresh read, wait for a character */ X if ((c = ttinc(0)) < 0) { /* Comm line hangup detected*/ X printf("\r\nC-Kermit: Communications line failure\r\n"); X kill(parent_id,SIGUSR1); /* notify parent. */ X pause(); /* Wait to be killed by parent. */ X } X c &= 0177; /* Got a char, strip parity. */ X conoc(c); /* Put it on the screen. */ X if (seslog) zchout(ZSFILE,c); /* If logging, log it. */ X n = ttchk(); /* Any more left in buffer? */ X if (n > 0) { X if (n > LBUFL) n = LBUFL; /* Get them all at once. */ X if ((n = ttxin(n,lbuf)) > 0) { X for (i = 0; i < n; i++) lbuf[i] &= 0177; X conxo(n,lbuf); X if (seslog) zsoutx(ZSFILE,lbuf,n); X } X } X } X } X} X X/* H C O N N E -- Give help message for connect. */ X Xhconne() { X int c; X static char *hlpmsg[] = {"\ X\r\nC to close the connection, or:", X"\r\n S for status", X"\r\n ? for help", X"\r\n B to send a BREAK", X"\r\n 0 to send a null", X"\r\n escape character twice to send the escape character.\r\n\r\n", X"" }; X X conola(hlpmsg); /* Print the help message. */ X conol("Command>"); /* Prompt for command. */ X c = coninc(0); X conoc(c); /* Echo it. */ X conoll(""); X c &= 0177; /* Strip any parity. */ X return(c); /* Return it. */ X} X X X/* C H S T R -- Make a printable string out of a character */ X Xchar * Xchstr(c) int c; { X static char s[8]; X char *cp = s; X X if (c < SP) { X sprintf(cp,"CTRL-%c",ctl(c)); X } else sprintf(cp,"'%c'\n",c); X cp = s; X return(cp); X} X X/* D O E S C -- Process an escape character argument */ X Xdoesc(c) char c; { X int d; X X c &= 0177; X while (1) { X if (c == escape) { /* Send escape character */ X d = dopar(c); X ttoc(d); X return; X } else /* Or else look it up below. */ X if (isupper(c)) c = tolower(c); X X switch (c) { X X case 'c': /* Close connection */ X case '\03': X active = 0; X conol("\r\n"); X return; X X case 'b': /* Send a BREAK */ X case '\02': X ttsndb(); X return; X X case 's': /* Status */ X case '\023': X conol("\r\nConnected thru "); X conoll(ttname); X if (seslog) { X conol(", logging to "); X conol(sesfil); X } X return; X X case '?': /* Help */ X c = hconne(); X continue; X X case '0': /* Send a null */ X c = '\0'; X d = dopar(c); X ttoc(d); X return; X X case SP: /* Space, ignore */ X return; X X default: /* Other */ X conoc(BEL); /* Invalid esc arg, beep */ X return; X } X } X} !FUNKY!STUFF! echo x - ckdial.c sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckdial.c Xchar *dialv = "Dial Command for Unix, V0.0(005) 5 Mar 85"; X X/* C K D I A L -- Dialing program for connection to remote system */ X X/* X This module should work under all versions of Unix. It calls externally X defined system-depended functions for i/o, but depends upon the existence X of various modem control functions. X X Author: Herm Fischer, Litton Data Systems, Van Nuys CA (HFISCHER@USC-ECLB) X*/ X X#include "ckermi.h" X#include <signal.h> X#include <setjmp.h> X#include "ckcmd.h" X Xextern int local, speed, flow, mdmtyp; Xextern char ttname[], sesfil[]; X X#define HAYES 1 /* for mdmtyp settings */ X#define VENTEL 2 X#define HAYESNV 3 /* internal use, non-verbal V0 setting */ X Xstruct keytab mdmtab[] = { /* Modem types for command parsing */ X "direct", 0, 0, X "hayes", HAYES, 0, X "ventel", VENTEL, 0 X}; Xint nmdm = (sizeof(mdmtab) / sizeof(struct keytab)); X X#define DIALING 4 /* for ttvt parameter */ X#define CONNECT 5 X X#define CONNECTED 1 /* for completion status */ X#define FAILED 2 X Xstatic int tries = 0; X X#define LBUFL 100 Xstatic char lbuf[LBUFL]; Xstatic char *lbp; X Xstatic jmp_buf sjbuf; X Xstatic Xtimerh() { /* timer interrupt handler */ X longjmp(sjbuf,1); X} X Xstatic Xstripp(s) char *s; { /* parity stripper aid */ X for ( ; *s ; *s++ &= 0177 ); X} X X/* D I A L -- Dial up the remote system */ X Xdial(telnbr) char *telnbr; { X X char c; X char *i; X int waitct, status; X char errmsg[50], *erp; X int augMdm; /* mdmtyp with switch settings added */ X int mdmEcho = 0; /* assume modem does not echo */ X int n; X int (*savAlrm)(); /* save incomming alarm function */ X X if (!mdmtyp) { X printf("Sorry, you must 'set modem' first\n"); X return(-2); X } X augMdm = mdmtyp; /* internal use, to add dialer switches info*/ X X if (!local) { X printf("Sorry, you must 'set line' first\n"); X return(-2); X } X if (speed < 0) { X printf("Sorry, you must 'set speed' first\n"); X return(-2); X } X if (ttopen(ttname,local,mdmtyp) < 0) {/* Open, no wait for carrier */ X erp = errmsg; X sprintf(erp,"Sorry, can't open %s",ttname); X perror(errmsg); X return(-2); X } X/* cont'd... */ X /* interdigit waits for tone dial */ X/* ...dial, cont'd */ X X X waitct = 1*strlen(telnbr) ; /* compute time to dial worst case */ X switch (augMdm) { X case HAYES: X case HAYESNV: X waitct += 35; /* dial tone + carrier waits + slop */ X for (i=telnbr; *i; i++) if (*i == ',') waitct += 2; X break; X case VENTEL: X waitct += 10; /* guess actual time for dialtones */ X waitct += 10; /* ventel's apparent patience for carrier */ X for (i=telnbr; *i; i++) if (*i == '%') waitct += 5; X break; X } X X printf("Dialing thru %s, speed %d, number %s.\r\n",ttname,speed,telnbr); X printf("The timeout for completing the call is %d seconds.\r\n",waitct); X X/* Condition console terminal and communication line */ X /* place line into "clocal" dialing state */ X if ( ttpkt(speed,DIALING) < 0 ) { X printf("Sorry, Can't condition communication line\n"); X return(-2); X } X X/* Put modem into command state */ X X savAlrm = signal(SIGALRM,timerh); X alarm(10); /* give modem 10 seconds to wake up */ X if (setjmp(sjbuf)) { X alarm(0); X signal(SIGALRM,savAlrm); /* cancel timer */ X ttpkt(speed,CONNECT); /* cancel dialing state ioctl */ X printf("Sorry, unable to complete dialed connection\r\n"); X return(-2); X } X ttflui(); /* flush input buffer if any */ X X#define OKAY 1 /* modem attention attempt status */ X#define IGNORE 2 X#define GOT_O -2 X#define GOT_A -3 X Xswitch (augMdm) { X case HAYES: X case HAYESNV: X while(tries++ < 4) { X ttol("AT\r",3); /* signal for attention, look for response */ X status = 0; X while ( status <= 0 ) { X switch (ttinc(0) & 0177) { X case 'A': /* echoing, ignore */ X status = GOT_A; X break; X case 'T': X if (status == GOT_A) { X mdmEcho = 1; /* expect echoing later */ X status = 0; X break; X } X status = IGNORE; X break; X case '\n': X case '\r': X status = 0; X break; X case '0': /* numeric result code */ X augMdm = HAYESNV; /* nonverbal result codes */ X status = OKAY; X break; X case 'O': /* maybe English result code*/ X status = GOT_O; X break; X case 'K': X if (status == GOT_O) { X augMdm = HAYES; X status = OKAY; X break; X } /* else its default anyway */ X default: X status = IGNORE; X break; X } X } X if (status == OKAY) break; X if (status == IGNORE) ttflui(); X sleep(1); /* wait before retrying */ X } X if (status != 0) break; X printf("Sorry, can't initialize modem\n"); X ttpkt(speed,CONNECT); /* cancel dialing state ioctl */ X alarm(0); X signal(SIGALRM,savAlrm); /* cancel timer */ X return(-2); X X/* cont'd... */ X /* interdigit waits for tone dial */ X/* ...dial, cont'd */ X X case VENTEL: X ttoc('\r'); /* Put Ventel into command mode */ X sleep(1); X ttoc('\r'); X sleep(1); X ttoc('\r'); X while( (ttinc(0) & 0177) != '$'); X break; X } X alarm(0); /* turn off alarm */ X sleep(1); /* give things settling time */ X X X/* Dial the number */ X Xswitch (augMdm) { X case HAYES: X case HAYESNV: X sprintf(lbuf,"AT DT %s\r",telnbr); X break; X case VENTEL: X sprintf(lbuf,"<K%s\r>",telnbr); X break; X } X X alarm(waitct); /* time to allow for connecting */ X ttflui(); /* clear out stuff from waking modem up */ X ttol(lbuf,strlen(lbuf)); /* send dialing string */ X X/* cont'd... */ X /* interdigit waits for tone dial */ X/* ...dial, cont'd */ X X X/* Check for connection */ X X status = 0; X while (status == 0) { X switch (augMdm) { X case HAYES: X for (n = 0; n < LBUFL; n++) lbuf[n] = '\0'; X n = ttinl(lbuf,LBUFL,0,'\n'); X if (n > 2) { X lbp = lbuf; X while ((*lbp == '\r') || (*lbp == '\n')) lbp++; X stripp(lbp); X if (strncmp(lbp,"CONNECT",7) == 0) status = CONNECTED; X if (strncmp(lbp,"NO CARRIER",10) == 0) status = FAILED; X } X break; X X case HAYESNV: X c = ttinc(0) & 0177; X if (mdmEcho) { /* sponge up dialing string */ X mdmEcho = c!='\r'; /* until return is echoed */ X break; X } X if (c == '1') status = CONNECTED; X if (c == '3') status = FAILED; X if (c == '5') status = CONNECTED; X break; X X case VENTEL: X if ( (ttinc(0) & 0177) == '!') status = CONNECTED; X break; X } X } X X/* Place line into modem-control (non-clocal) state */ X X if (status == 0) printf("Sorry, Can't get response from modem\r\n"); X else if (status == CONNECTED) printf("Connected!\r\n"); X else if (status == FAILED) printf("Sorry, No Carrier\r\n"); X else printf("Failed to complete call\r\n"); X X ttpkt(speed,CONNECT); /* cancel dialing state ioctl */ X alarm(0); X signal(SIGALRM,savAlrm); /* cancel timer */ X return((status==CONNECTED) ? 0 : -2); X} !FUNKY!STUFF!
oz@yetti.UUCP (Ozan Yigit) (03/24/85)
Problem: C-kermit (release 4.n) "help set" or "help remote" commands will core dump on Pro VENIX due to the size limitation on the printf format string. (These help commands use the help string as the format string, instead of printf("%s",str)). File: ckusr2.c Fix: Add the missing "%s" where necessary. Incl.: diff output for fixes Oz Dept. of Computer Science York University decvax{utzoo|utcs}!yetti!oz -------- DIFF OUTPUT - C U T H E R E ------------------------------ 305c305 < printf(hmhset); --- > printf("%s",hmhset); 312c312 < printf(hmxychkt); --- > printf("%s",hmxychkt); 316c316 < printf("\ --- > printf("%s","\ 321c321 < printf("\ --- > printf("%s","\ 327c327 < printf("\ --- > printf("%s","\ 333c333 < printf("\ --- > printf("%s","\ 339,342c339,342 < printf(hmxyf[0]); < printf(hmxyf[1]); < printf(hmxyf[2]); < printf(hmxyf[3]); --- > printf("%s",hmxyf[0]); > printf("%s",hmxyf[1]); > printf("%s",hmxyf[2]); > printf("%s",hmxyf[3]); 346c346 < printf("\ --- > printf("%s","\ 352c352 < printf("\ --- > printf("%s","\ 358c358 < printf("\ --- > printf("%s","\ 366c366 < printf("\ --- > printf("%s","\ 368c368 < printf("\ --- > printf("%s","\ 372c372 < printf("\ --- > printf("%s","\ 379c379 < printf("\ --- > printf("%s","\ 385c385 < printf("\ --- > printf("%s","\ 392c392 < printf("\ --- > printf("%s","\ 397c397 < printf("Decimal ASCII value of inbound padding character, normally 0.\n"); --- > printf("%s","Decimal ASCII value of inbound padding character, normally 0.\n"); 401c401 < printf("\ --- > printf("%s","\ 407c407 < printf("Prompt string for this program, normally 'C-Kermit>'.\n"); --- > printf("%s","Prompt string for this program, normally 'C-Kermit>'.\n"); 411c411 < printf("\ --- > printf("%s","\ 418c418 < printf("\ --- > printf("%s","\ 433,434c433,434 < printf(hmhrmt[0]); < printf(hmhrmt[1]); --- > printf("%s",hmhrmt[0]); > printf("%s",hmhrmt[1]);