imported 9.0.300
[ckermit.git] / ckcplm.txt
diff --git a/ckcplm.txt b/ckcplm.txt
new file mode 100644 (file)
index 0000000..9829987
--- /dev/null
@@ -0,0 +1,3046 @@
+
+   [1]The Columbia Crown The Kermit Project | Columbia University
+   612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+   ...since 1981
+   [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+   [10]Support
+
+C-Kermit Program Logic Manual
+
+     Frank da Cruz
+     [11]The Kermit Project
+     [12]Columbia University
+
+   As of: C-Kermit 9.0.300, 30 June 2011
+   Last update: Tue Jun 28 08:59:18 2011
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+     this file is a plain-text dump of a Web page. You can visit the
+     original (and possibly more up-to-date) Web page here:
+
+  [13]http://www.columbia.edu/kermit/ckcplm.html
+
+   [ [14]C-Kermit Home ] [ [15]Kermit Home ]
+
+CONTENTS
+
+  1. [16]INTRODUCTION
+  2. [17]FILES
+  3. [18]SOURCE CODE PORTABILITY AND STYLE
+  4. [19]MODULES
+     4.A. [20]Group A: Library Routines
+     4.B. [21]Group B: Kermit File Transfer
+     4.C. [22]Group C: Character-Set Conversion
+     4.D. [23]Group D: User Interface
+     4.E. [24]Group E: Platform-Dependent I/O
+     4.F. [25]Group F: Network Support
+     4.G. [26]Group G: Formatted Screen Support
+     4.H. [27]Group H: Pseudoterminal Support
+     4.I. [28]Group I: Security
+  I. [29]APPENDIX I: FILE PERMISSIONS
+
+1. INTRODUCTION
+
+   The Kermit Protocol is specified in the book Kermit, A File Transfer
+   Protocol by Frank da Cruz, Digital Press / Butterworth Heinemann,
+   Newton, MA, USA (1987), 379 pages, ISBN 0-932376-88-6. It is assumed
+   the reader is familiar with the Kermit protocol specification.
+
+   This file describes the relationship among the modules and functions of
+   C-Kermit 5A and later, and other programming considerations. C-Kermit
+   is designed to be portable to any kind of computer that has a C
+   compiler. The source code is broken into many files that are grouped
+   according to their function, as shown in the [30]Contents.
+
+   C-Kermit has seen constant development since 1985. Throughout its
+   history, there has been a neverending tug-of-war among:
+
+    a. Functionality: adding new features, fixing bugs, improving
+       performance.
+    b. Adding support for new platforms.
+    c. "Buzzword 1.0 compliance".
+
+   The latter category is the most frustrating, since it generally
+   involves massive changes just to keep the software doing what it did
+   before in some new setting: e.g. the K&R-to-ANSIC conversion (which had
+   to be done, of course, without breaking K&R); Y2K (not a big deal in
+   our case); the many and varied UNIX and other API "standards"; IPv6.
+
+   [ [31]Contents ] [ [32]C-Kermit ] [ [33]Kermit Home ]
+
+2. FILES
+
+   C-Kermit source files begin with the two letters "ck", for example
+   ckutio.c. Filenames are kept short (6.3) for maximum portability and
+   (obviously I hope) do not contain spaces or more than one period. The
+   third character in the name denotes something about the function group
+   and the expected level of portability:
+
+     a     General descriptive material and documentation (text)
+     b     BOO file encoders and decoders (obsolete)
+     c     All platforms with C compilers (*)
+     d     Data General AOS/VS
+     e     Reserved for "ckermit" files, like ckermit.ini, ckermit2.txt
+     f     (reserved)
+     g     (reserved)
+     h     (reserved)
+     i     Commodore Amiga (Intuition)
+     j     (unused)
+     k     (unused)
+     l     Stratus VOS
+     m     Macintosh with Mac OS 1-9
+     n     Microsoft Windows NT/2000/XP
+     o     OS/2 and/or Microsoft Windows 9x/ME/NT/2000/XP
+     p     Plan 9 from Bell Labs
+     q     (reserved)
+     r     DEC PDP-11 with RSTS/E (never used, open for reassigment)
+     s     Atari ST GEMDOS (last supported in version 5A(189))
+     t     DEC PDP-11 with RT-11 (never used, open for reassigment)
+     u     Unix-based operating systems (*)
+     v     VMS and OpenVMS
+     w     Wart (Lex-like preprocessor, platform independent)
+     x     (reserved)
+     y     (reserved)
+     z     (reserved)
+     0-3   (reserved)
+     4     IBM AS/400
+     5-8   (reserved)
+     9     Microware OS-9
+     _     Encryption modules
+
+   (*) In fact there is little distinction between the ckc*.* and cku*.*
+   categories. It would make more sense for all cku*.* modules to be
+   ckc*.* ones, except ckufio.c, ckutio.c, ckucon.c, ckucns.c, and
+   ckupty.c, which truly are specific to Unix. The rest (ckuus*.c,
+   ckucmd.c, etc) are quite portable.
+
+   One hint before proceeding: functions are scattered all over the ckc*.c
+   and cku*.c modules, where function size has begun to take precedence
+   over the desirability of grouping related functions together, the aim
+   being to keep any particular module from growing disproportionately
+   large. The easiest way (in UNIX) to find out in what source file a
+   given function is defined is like this (where the desired function is
+   foo()...):
+
+  grep ^foo\( ck*.c
+
+   This works because the coding convention has been to make function
+   names always start on the left margin with their contents indented, for
+   example:
+
+static char *
+foo(x,y) int x, y; {
+    ...
+}
+
+   Also note the style for bracket placement. This allows bracket-matching
+   text editors (such as EMACS) to help you make sure you know which
+   opening bracket a closing bracket matches, particularly when the
+   opening bracket is above the visible screen, and it also makes it easy
+   to find the end of a function (search for '}' on the left margin).
+
+   Of course EMACS tags work nicely with this format too:
+
+  $ cd kermit-source-directory
+  $ etags ck[cu]*.c
+  $ emacs
+  Esc-X Visit-Tags-Table<CR><CR>
+
+   (but remember that the source file for ckcpro.c is [34]ckcpro.w!)
+
+   Also:
+
+     * Tabs should be set every 8 spaces, as on a VT100.
+     * All lines must no more than 79 characters wide after tab expansion.
+     * Note the distinction between physical tabs (ASCII 9) and the
+       indentation conventions, which are: 4 for block contents, 2 for
+       most other stuff (obviously this is not a portability issue, just
+       style).
+
+   [ [35]Contents ] [ [36]C-Kermit ] [ [37]Kermit Home ]
+
+3. SOURCE CODE PORTABILITY AND STYLE
+
+   C-Kermit was designed in 1985 as a platform-independent replacement for
+   the earlier Unix Kermit. c-Kermit's design was expected to promote
+   portability, and judging from the number of platforms to which it has
+   been adapted since then, the model is effective, if not ideal
+   (obviously if we had it all to do over, we'd change a few things). To
+   answer the oft-repeated question: "Why are there so many #ifdefs?",
+   it's because:
+
+     * Many of them are related to feature selection and program size, and
+       so need to be there anyway.
+     * Those that treat compiler, library, platform, header-file, and
+       similar differences have built up over time as hundreds of people
+       all over the world adapted C-Kermit to their particular
+       environments and sent back their changes. There might be more
+       politically-correct ways to achieve portability, but this one is
+       natural and proven. The basic idea is to introduce changes that can
+       be selected by defining a symbol, which, if not defined, leaves the
+       program exactly as it was before the changes.
+     * Although it might be possible to "clean up" the "#ifdef mess",
+       nobody has access to all the hundreds of platforms served by the
+       #ifdefs to check the results.
+
+   And to answer the second-most-oft-repeated question: "Why don't you
+   just use GNU autoconfig / automake / autowhatever instead of
+   hard-coding all those #ifdefs?" Answers:
+
+     * The GNU tools are not available on all the platforms where C-Kermit
+       must be built and I wouldn't necessarily trust them if they were.
+     * Each platform is a moving target, so the tools themselves would
+       need to updated before Kermit could be updated.
+     * It would only add another layer of complexity to an already complex
+       process.
+     * Conversion at this point would not be practical unless there was a
+       way to test the results on all the hundreds of platforms where
+       C-Kermit is supposed to build.
+
+   When writing code for the system-indendent C-Kermit modules, please
+   stick to the following coding conventions to ensure portability to the
+   widest possible variety of C preprocessors, compilers, and linkers, as
+   well as certain network and/or email transports. The same holds true
+   for many of the "system dependent" modules too; particularly the Unix
+   ones, since they must be buildable by a wide variety of compilers and
+   linkers, new and old.
+
+   This list does not purport to be comprehensive, and although some items
+   on it might seem far-fetched, they would not be listed unless I had
+   encountered them somewhere, some time. I wish I had kept better records
+   so I could cite specific platforms and compilers.
+
+     * Try to keep variable and function names unique within 6 characters,
+       especially if they are used across modules, since 6 is the maximum
+       for some old linkers (actually, this goes back to TOPS-10 and -20
+       and other old DEC OS's where C-Kermit never ran anyway; a more
+       realistic maximum is probably somewhere between 8 and 16). We know
+       for certain that VAX C has a 31-character max because it complains
+       -- others might not complain, but just silently truncate, thus
+       folding two or more routines/variables into one.
+     * Keep preprocessor symbols unique within 8 characters; that's the
+       max for some preprocessors (sorry, I can't give a specific example,
+       but in 1988 or thereabouts, I had to change character-set symbols
+       like TC_LATIN1 and TC_LATIN2 to TC_1LATIN and TC_2LATIN because the
+       digits were being truncated and ignored on a platform where I
+       actually had to build C-Kermit 5A; unfortunately I didn't note
+       which platform -- maybe some early Ultrix version?)
+     * Don't create preprocessor symbols, or variable or function names,
+       that start with underscore (_). These are usually reserved for
+       internal use by the compiler and header files.
+     * Don't put #include directives inside functions or { blocks }.
+     * Don't use the #if or #elif preprocessor constructions, only use
+       #ifdef, #ifndef, #define, #undef, and #endif.
+     * Put tokens after #endif in comment brackets, e.g. #endif /* FOO */.
+     * Don't indent preprocessor statements - # must always be first char
+       on line.
+     * Don't put whitespace after # in preprocessor statements.
+     * Don't use #pragma, even within #ifdefs -- it makes some
+       preprocessors give up.
+     * Same goes for #module, #if, etc - #ifdefs do NOT protect them.
+     * Don't use logical operators in preprocessor constructions.
+     * Avoid #ifdefs inside argument list to function calls (I can't
+       remember why this one is here, but probably needn't be; we do this
+       all the time).
+     * Always cast strlen() in expressions to int:
+       if ((int)strlen(foo) < x)...
+     * Any variable whose value might exceed 16383 should be declared as
+       long, or if that is not possible, then as unsigned.
+     * Avoid typedefs; they might be portable but they are very confusing
+       and there's no way to test for their presence or absence at compile
+       time. Use preprocessor symbols instead if possible; at least you
+       can test their definitions.
+     * Unsigned long is not portable; use a preprocessor symbol (Kermit
+       uses ULONG for this).
+     * Long long is not portable. If you really need it, be creative.
+     * Similarly 1234LL is not portable, nor almost any other constant
+       modifier other than L.
+     * Unsigned char is not portable, use CHAR (a preprocessor symbol
+       defined in the Kermit header files) and always take precautions
+       against character signage (more about this [38]below).
+     * Don't use initializers with automatic arrays or structs: it's not
+       portable.
+     * Don't use big automatic arrays or structs in functions that might
+       be called recursively; some platforms have fixed-size stacks (e.g.
+       Windows 9x: 256K) and recursive functions crash with stack
+       overflow. Even when there is not a compiler limitation, this causes
+       memory to be consumed without bound, and can end up filling swap
+       space.
+     * Don't assume that struct assignment performs a copy, or that it
+       even exists.
+     * Don't use sizeof to get the size of an array; someone might come
+       along later and and change it from static to malloc'd. Always use a
+       symbol to refer to the array's size.
+     * Don't put prototypes for static functions into header files that
+       are used by modules that don't contain that function; the link step
+       can fail with unresolved references (e.g. on AOS/VS).
+     * Avoid the construction *++p (the order of evaluation varies; it
+       shouldn't but at least one compiler had a bug that made me include
+       this item).
+     * Don't use triple assignments, like a = b = c = 0; (or quadruple,
+       etc). Some compilers generate bad code for these, or crash, etc
+       (some version of DEC C as I recall).
+     * Some compilers don't allow structure members to have the same names
+       as other identifiers. Try to give structure members unique names.
+     * Don't assume anything about order of evaluation in boolean
+       expressions, or that they will stop early if a required condition
+       is not true, e.g.:
+  if (i > 0 && p[i-1] == blah)
+
+       can still dump core if i == 0 (hopefully this is not true of any
+       modern compiler, but I would not have said this if it did not
+       actually happen somewhere).
+     * Don't have a switch() statement with no cases (e.g. because of
+       #ifdefs); this is a fatal error in some compilers.
+     * Don't put lots of code in a switch case; move it out to a separate
+       function; some compilers run out of memory when presented with a
+       huge switch() statement -- it's not the number of cases that
+       matters; it's the overall amount of code.
+     * Some compilers might also limit the number of switch() cases, e.g.
+       to 254.
+     * Don't put anything between "switch() {" and "case:" -- switch
+       blocks are not like other blocks.
+     * Don't jump into or out of switches.
+     * Don't make character-string constants longer than about 250 bytes.
+       Longer strings should be broken up into arrays of strings.
+     * Don't write into character-string constants (obviously). Even when
+       you know you are not writing past the end; the compiler or linker
+       might have put them into read-only and/or shared memory, and/or
+       coalesced multiple equal constants so if you change one you change
+       them all.
+     * Don't depend on '\r' being carriage return.
+     * Don't depend on '\n' being linefeed or for that matter any SINGLE
+       character.
+     * Don't depend on '\r' and '\n' being different (e.g. as separate
+       switch() cases).
+     * In other words, don't use \n or \r to stand for specific
+       characters; use \012 and \015 instead.
+     * Don't code for "buzzword 1.0 compliance", unless "buzzword" is K&R
+       and "1.0" is the first edition.
+     * Don't use or depend on anything_t (size_t, pid_t, etc), except
+       time_t, without #ifdef protection (time_t is the only one I've
+       found that is accepted everywhere). This is a tough one because the
+       same function might require (say) a size_t arg on one platform,
+       whereas size_t is unheard of on another; or worse, it might require
+       a totally different data type, like int or long or some other
+       typedef'd thing. It has often proved necessary to define a symbol
+       to stand for the type of a particular argument to a particular
+       library or system function to get around this problem.
+     * Don't use or depend on internationalization ("i18n") features,
+       wchar_t, locales, etc, in portable code; they are not portable.
+       Anyway, locales are not the right model for Kermit's
+       multi-character-set support. Kermit does all character-set
+       conversion itself and does not use any external libraries or
+       functions.
+     * In particular, don't use any library functions that deal with wide
+       characters or Unicode in any form. These are not only nonportable,
+       but a constantly shifting target (e.g. the ones in glibc).
+     * Don't make any assumption about signal handler type. It can be
+       void, int, long, or anything else. Always declare signal handlers
+       as SIGTYP (see definition in ckcdeb.h and augment it if necessary)
+       and always use SIGRETURN at exit points from signal handlers.
+     * Signals should always be re-armed to be used again (this barely
+       scratches the surface -- the differences between BSD/V7 and System
+       V and POSIX signal handling are numerous, and some platforms do not
+       even support signals, alarms, or longjmps correctly or at all --
+       avoid all of this if you can).
+     * On the other hand, don't assume that signals are disarmed after
+       being raised. In some platforms you have to re-arm them, in others
+       they stay armed.
+     * Don't call malloc() and friends from a signal handler; don't do
+       anything but setting integer global variables in a signal handler.
+     * malloc() does not initialize allocated memory -- it never said it
+       did. Don't expect it to be all 0's.
+     * Did You Know: malloc() can succeed and the program can still dump
+       core later when it attempts to use the malloc'd memory? (This
+       happens when allocation is deferred until use and swap space is
+       full.)
+     * memset(), memmove(), and memcpy() are not portable, don't use them
+       without protecting them in ifdefs (we have USE_MEMCPY for this).
+       bzero()/bcopy() too, except we're guaranteed to have
+       bzero()/bcopy() when using the sockets library (not really). See
+       examples in the source.
+     * Don't assume that strncpy() stops on the first null byte -- most
+       versions always copy the number of bytes given in arg 3, padding
+       out with 0's and overwriting whatever was there before. Use
+       C-Kermit ckstrncpy() if you want predictable non-padding behavior,
+       guaranteed NUL-termination, and a useful return code.
+     * DID YOU KNOW.. that some versions of inet_blah() routines return IP
+       addresses in network byte order, while others return them local
+       machine byte order? So passing them to ntohs() or whatever is not
+       always the right thing to do.
+     * Don't use ANSI-format function declarations without #ifdef
+       CK_ANSIC, and always provide an #else for the non-ANSI case.
+     * Use the Kermit _PROTOTYP() macro for declaring function prototypes;
+       it works in both the ANSI and non-ANSI cases.
+     * Don't depend on any other ANSI preprocessor features like "pasting"
+       -- they are often missing or nonoperational.
+     * Don't assume any C++ syntax or semantics.
+     * Don't use // as a comment introducer. C is not C++.
+     * Don't declare a string as "char foo[]" in one module and "extern
+       char * foo" in another, or vice-versa: this causes core dumps.
+     * With compiler makers falling all over themselves trying to outdo
+       each other in ANSI strictness, it has become increasingly necessary
+       to cast EVERYTHING. This is increasingly true for char vs unsigned
+       char. We need to use unsigned chars if we want to deal with 8-bit
+       character sets, but most character- and string-oriented APIs want
+       (signed) char arguments, so explicit casts are necessary. It would
+       be nice if every compiler had a -funsigned-char option (as gcc
+       does), but they don't.
+     * a[x], where x is an unsigned char, can produce a wild memory
+       reference if x, when promoted to an int, becomes negative. Cast it
+       to (unsigned), even though it ALREADY IS unsigned.
+     * Be careful how you declare functions that have char or long
+       arguments; for ANSI compilers you MUST use ANSI declarations to
+       avoid promotion problems, but you can't use ANSI declarations with
+       non-ANSI compilers. Thus declarations of such functions must be
+       hideously entwined in #ifdefs. Example: latter:
+  int                          /*  Put character in server command buffer  */
+  #ifdef CK_ANSIC
+  putsrv(char c)
+  #else
+  putsrv(c) char c;
+  #endif /* CK_ANSIC */
+  /* putsrv */ {
+      *srvptr++ = c;
+      *srvptr = '\0';           /* Make sure buffer is null-terminated */
+      return(0);
+  }
+
+     * Be careful how you return characters from functions that return int
+       values -- "getc-like functions" -- in the ANSI world. Unless you
+       explicitly cast the return value to (unsigned), it is likely to be
+       "promoted" to an int and have its sign extended.
+     * At least one compiler (the one on DEC OSF/1 1.3) treats "/*" and
+       "*/" within string constants as comment begin and end. No amount of
+       #ifdefs will get around this one. You simply can't put these
+       sequences in a string constant, e.g. "/usr/local/doc/*.*".
+     * Avoid putting multiple macro references on a single line, e.g.:
+  putchar(BS); putchar(SP); putchar(BS)
+
+   This overflows the CPP output buffer of more than a few C preprocessors
+   (this happened, for example, with SunOS 4.1 cc, which evidently has a
+   1K macro expansion buffer).
+
+   C-Kermit needs constant adjustment to new OS and compiler releases.
+   Every new OS release shuffles header files or their contents, or
+   prototypes, or data types, or levels of ANSI strictness, etc. Every
+   time you make an adjustment to remove a new compilation error, BE VERY
+   CAREFUL to #ifdef it on a symbol unique to the new configuration so
+   that the previous configuration (and all other configurations on all
+   other platforms) remain as before.
+
+   Assume nothing. Don't assume header files are where they are supposed
+   to be, that they contain what you think they contain, that they define
+   specific symbols to have certain values -- or define them at all! Don't
+   assume system header files protect themselves against multiple
+   inclusion. Don't assume that particular system or library calls are
+   available, or that the arguments are what you think they are -- order,
+   data type, passed by reference vs value, etc. Be conservative when
+   attempting to write portable code. Avoid all advanced features.
+
+   If you see something that does not make sense, don't assume it's a
+   mistake -- it might be there for a reason, and changing it or removing
+   is likely to cause compilation, linking, or runtime failures sometime,
+   somewhere. Some huge percentage of the code, especially in the
+   platform-dependent modules, is workarounds for compiler, linker, or API
+   bugs.
+
+   But finally... feel free to violate any or all of these rules in
+   platform-specific modules for environments in which the rules are
+   certain not to apply. For example, in VMS-specific code, it is OK to
+   use #if, because VAX C, DEC C, and VMS GCC all support it.
+
+   [ [39]Contents ] [ [40]C-Kermit ] [ [41]Kermit Home ]
+
+3.1. Memory Leaks
+
+   The C language and standard C library are notoriously inadequate and
+   unsafe. Strings are arrays of characters, usually referenced through
+   pointers. There is no native string datatype. Buffers are fixed size,
+   and C provides no runtime bounds checking, thus allowing overwriting of
+   other data or even program code. With the popularization of the
+   Internet, the "buffer exploit" has become a preferred method for
+   hackers to hijack privileged programs; long data strings are fed to a
+   program in hopes that it uses unsafe C library calls such as strcpy()
+   or sprintf() to copy strings into automatic arrays, thus overwriting
+   the call stack, and therefore the routine's return address. When such a
+   hole is discovered, a "string" can be constructed that contains machine
+   code to hijack the program's privileges and penetrate the system.
+
+   This problem is partially addressed by the strn...() routines, which
+   should always be used in preference to their str...() equivalents
+   (except when the copy operation has already been prechecked, or there
+   is a good reason for not using them, e.g. the sometimes undesirable
+   side effect of strncpy() zeroing the remainder of the buffer). The most
+   gaping whole, however, is sprintf(), which performs no length checking
+   on its destination buffer, and is not easy to replace. Although
+   snprintf() routines are starting to appear, they are not yet
+   widespread, and certainly not universal, nor are they especially
+   portable, or even full-featured.
+
+   For these reasons, we have started to build up our own little library
+   of C Library replacements, ckclib.[ch]. These are safe and highly
+   portable primitives for memory management and string manipulation, such
+   as:
+
+   ckstrncpy()
+          Like strncpy but returns a useful value, doesn't zero buffer.
+
+   ckitoa()
+          Opposite of atoi()
+
+   ckltoa()
+          Opposite of atol()
+
+   ckctoa()
+          Returns character as string
+
+   ckmakmsg()
+          Used with ck?to?() as a safe sprintf() replacement for up to 4
+          items
+
+   ckmakxmsg()
+          Like ckmakmsg() but accepts up to 12 items
+
+   More about library functions in [42]Section 4.A.
+
+   [ [43]Contents ] [ [44]C-Kermit ] [ [45]Kermit Home ]
+
+3.2. The "char" vs "unsigned char" Dilemma
+
+   This is one of the most aggravating and vexing characteristics of the C
+   language. By design, chars (and char *'s) are SIGNED. But in the modern
+   era, however, we need to process characters that can have (or include)
+   8-bit values, as in the ISO Latin-1, IBM CP 850, or UTF-8 character
+   sets, so this data must be treated as unsigned. But some C compilers
+   (such as those based on the Bell UNIX V7 compiler) do not support
+   "unsigned char" as a data type. Therefore we have the macro or typedef
+   CHAR, which we use when we need chars to be unsigned, but which,
+   unfortunately, resolves itself to "char" on those compilers that don't
+   support "unsigned char". AND SO... We have to do a lot of fiddling at
+   runtime to avoid sign extension and so forth.
+
+   Some modern compilers (e.g. IBM, DEC, Microsoft) have options that say
+   "make all chars be unsigned" (e.g. GCC "-funsigned-char") and we use
+   them when they are available. Other compilers don't have this option,
+   and at the same time, are becoming increasingly strict about type
+   mismatches, and spew out torrents of warnings when we use a CHAR where
+   a char is expected, or vice versa. We fix these one by one using casts,
+   and the code becomes increasingly ugly. But there remains a serious
+   problem, namely that certain library and kernel functions have
+   arguments that are declared as signed chars (or pointers to them),
+   whereas our character data is unsigned. Fine, we can can use casts here
+   too -- but who knows what happens inside these routines.
+
+   [ [46]Contents ] [ [47]C-Kermit ] [ [48]Kermit Home ]
+
+4. MODULES
+
+   When C-Kermit is on the far end of a connection, it is said to be in
+   remote mode. When C-Kermit has made a connection to another computer,
+   it is in local mode. (If C-Kermit is "in the middle" of a multihop
+   connection, it is still in local mode.)
+
+   On another axis, C-Kermit can be in any of several major states:
+
+   Command State
+          Reading and writing from the job's controlling terminal or
+          "console". In this mode, all i/o is handled by the Group E
+          conxxx() (console i/o) routines.
+
+   Protocol State
+          Reading and writing from the communicatons device. In this mode,
+          all i/o is handled by the Group E ttxxx() (terminal i/o)
+          routines.
+
+   Terminal State
+          Reading from the keyboard with conxxx() routines and writing to
+          the communications device with ttxxx() routines AND vice-versa.
+
+   When in local mode, the console and communications device are distinct.
+   During file transfer, Kermit may put up a file-transfer display on the
+   console and sample the console for interruption signals.
+
+   When in remote mode, the console and communications device are the
+   same, and therefore there can be no file-transfer display on the
+   console or interruptions from it (except for "in-band" interruptions
+   such as ^C^C^C).
+
+   [ [49]Contents ] [ [50]C-Kermit ] [ [51]Kermit Home ]
+
+4.A. Group A: Library Functions
+
+   Library functions, strictly portable, can be used by all modules on all
+   platforms: [52]ckclib.h, [53]ckclib.c.
+
+   (To be filled in... For now, see [54]Section 3.1 and the comments in
+   ckclib.c.)
+
+   [ [55]Contents ] [ [56]C-Kermit ] [ [57]Kermit Home ]
+
+4.B. Group B: Kermit File Transfer
+
+   The Kermit protocol kernel. These files, whose names start with "ckc
+   are supposed to be totally portable C, and are expected to compile
+   correctly on any platform with any C compiler. "Portable" does not mean
+   the same as as "ANSI" -- these modules must compile on 10- and 20-year
+   old computers, with C preprocessors, compilers, and/or linkers that
+   have all sorts of restrictions. The Group B modules do not include any
+   header files other than those that come with Kermit itself. They do not
+   contain any library calls except from the standard C library (e.g.
+   printf()). They most certainly do not contain any system calls. Files:
+
+   [58]ckcsym.h
+          For use by C compilers that don't allow -D on the command line.
+
+   [59]ckcasc.h
+          ASCII character symbol definitions.
+
+   [60]ckcsig.h
+          System-independent signal-handling definitions and prototypes.
+
+   [61]ckcdeb.h
+          Originally, debugging definitions. Now this file also contains
+          all definitions and prototypes that are shared by all modules in
+          all groups.
+
+   [62]ckcker.h
+          Kermit protocol symbol definitions.
+
+   [63]ckcxla.h
+          Character-set-related symbol definitions (see next section).
+
+   [64]ckcmai.c
+          The main program. This module contains the declarations of all
+          the protocol-related global variables that are shared among the
+          other modules.
+
+   [65]ckcpro.w
+          The protocol module itself, written in "wart", a lex-like
+          preprocessor that is distributed with Kermit under the name
+          CKWART.C.
+
+   [66]ckcfns.c, [67]ckcfn2.c, [68]ckcfn3.c
+          The protocol support functions used by the protocol module.
+
+   [69]Group B modules may call upon functions from [70]Group E, but not
+   from [71]Group D modules (with the single exception that the main
+   program invokes the user interface, which is in Group D). (This last
+   assertion is really only a conjecture.)
+
+   [ [72]Contents ] [ [73]C-Kermit ] [ [74]Kermit Home ]
+
+4.C. Group C: Character-Set Conversion
+
+   Character set translation tables and functions. Used by the [75]Group
+   B, protocol modules, but may be specific to different computers. (So
+   far, all character character sets supported by C-Kermit are supported
+   in [76]ckuxla.c and [77]ckuxla.h, including Macintosh and IBM character
+   sets). These modules should be completely portable, and not rely on any
+   kind of system or library services.
+
+   [78]ckcxla.h
+          Character-set definitions usable by all versions of C-Kermit.
+
+   ck?xla.h
+          Character-set definitions for computer "?", e.g. [79]ckuxla.h
+          for UNIX, [80]ckmxla.h for Macintosh.
+
+   [81]ck?xla
+          Character-set translation tables and functions for computer "?",
+          For example, CKUXLA.C for UNIX, CKMXLA.C for Macintosh. So far,
+          these are the only two such modules. The UNIX module is used for
+          all versions of C-Kermit except the Macintosh version.
+
+   [82]ckcuni.h
+          Unicode definitions
+
+   [83]ckcuni.c
+          Unicode module
+
+   Here's how to add a new file character set in the original (non-Unicode
+   modules). Assuming it is based on the Roman (Latin) alphabet. Let's
+   call it "Barbarian". First, in ck?xla.h, add a definition for FC_BARBA
+   (8 chars maximum length) and increase MAXFCSETS by 1. Then, in
+   ck?xla.c:
+
+     * Add a barbarian entry into the fcsinfo array.
+     * Add a "barbarian" entry to file character set keyword table,
+       fcstab.
+     * Add a "barbarian" entry to terminal character set keyword table,
+       ttcstab.
+     * Add a translation table from Latin-1 to barbarian: yl1ba[].
+     * Add a translation table from barbarian to Latin-1: ybal1[].
+     * Add a translation function from Barbarian to ASCII: xbaas().
+     * Add a translation function from Barbarian to Latin-1: xbal1().
+     * Add a translation function from Latin-1 to Barbarian: xl1ba().
+     * etc etc for each transfer character set...
+     * Add translation function pointers to the xls and xlr tables.
+
+   Other translations involving Barbarian (e.g. from Barbarian to
+   Latin-Cyrillic) are performed through these tables and functions. See
+   ckuxla.h and ckuxla.c for extensive examples.
+
+   To add a new Transfer Character Set, e.g. Latin Alphabet 9 (for the
+   Euro symbol), again in the "old" character-set modules:
+
+   In ckcxla.h:
+
+          + Add a TC_xxxx definition and increase MAXTCSETS accordingly.
+
+   In ck?xla.h (since any transfer charset is also a file charset):
+
+          + Add an FC_xxxx definition and increase MAXFCSETS accordingly.
+
+   In ck?xla.c:
+
+          + Add a tcsinfo[] entry.
+          + Make a tcstab[] keyword table entry.
+          + Make an fcsinfo[] table entry.
+          + Make an fcstab[] keyword table entry.
+          + Make a tcstab[] keyword table entry.
+          + If necessary, make a langinfo[] table entry.
+          + Make entries in the function pointer arrays.
+          + Provide any needed functions.
+
+   As of C-Kermit 7.0, character sets are also handled in parallel by the
+   new (and very large) Unicode module, ckcuni.[ch]. Eventually we should
+   phase out the old way, described just above, and operate entirely in
+   (and through) Unicode. The advantages are many. The disadvantages are
+   size and performance. To add a character to the Unicode modules:
+
+   In ckcuni.h:
+
+          + (To be filled in...)
+
+   In ckcuni.c:
+
+          + (To be filled in...)
+
+   [ [84]Contents ] [ [85]C-Kermit ] [ [86]Kermit Home ]
+
+4.D. Group D: User Interface
+
+   This is the code that communicates with the user, gets her commands,
+   informs her of the results. It may be command-line oriented,
+   interactive prompting dialog, menus and arrow keys, windows and mice,
+   speech recognition, telepathy, etc. The one provided is command-and
+   prompt, with the ability to read commands from various sources: the
+   console keyboard, a file, or a macro definition. The user interface has
+   three major functions:
+
+    1. Sets the parameters for the file transfer and then starts it. This
+       is done by setting certain (many) global variables, such as the
+       protocol machine start state, the file specification, file type,
+       communication parameters, packet length, window size, character
+       set, etc.
+    2. Displays messages on the user's screen during the file transfer,
+       using the screen() function, which is called by the group-1
+       modules.
+    3. Executes any commands directly that do not require Kermit protocol,
+       such as the CONNECT command, local file management commands,
+       parameter-setting commands, FTP client commands, etc.
+
+   If you plan to imbed the [87]Group B, files into a program with a
+   different user interface, your interface must supply an appropriate
+   screen() function, plus a couple related ones like chkint() and
+   intmsg() for handling keyboard (or mouse, etc) interruptions during
+   file transfer. The best way to find out about this is to link all the
+   C-Kermit modules together except the ckuu*.o and ckucon.o modules, and
+   see which missing symbols turn up.
+
+   C-Kermit's character-oriented user interface (as opposed to the
+   Macintosh version's graphical user interface) consists of the following
+   modules. C-Kermit can be built with an interactive command parser, a
+   command-line-option-only parser, a graphical user interface, or any
+   combination, and it can even be built with no user interface at all (in
+   which case it runs as a remote-mode Kermit server).
+
+   [88]ckucmd.h
+   [89]ckucmd.c
+          The command parsing primitives used by the interactive command
+          parser to parse keywords, numbers, filenames, etc, and to give
+          help, complete fields, supply defaults, allow abbreviations and
+          editing, etc. This package is totally independent of Kermit, but
+          does depend on the [90]Group E functions.
+
+   [91]ckuusr.h
+          Definitions of symbols used in Kermit's commands.
+
+   ckuus*.c
+          Kermit's interactive command parser, including the script
+          programming language: [92]ckuusr.c (includes top-level keyword
+          tables); [93]ckuus2.c (HELP command text); [94]ckuus3.c (most of
+          the SET command); [95]ckuus4.c (includes variables and
+          functions); ckuus[567].c (miscellaneous);
+
+   [96]ckuusy.c
+          The command-line-option parser.
+
+   [97]ckuusx.c
+          User interface functions common to both the interactive and
+          command-line parsers.
+
+   [98]ckuver.h
+          Version heralds for different implementations.
+
+   [99]ckuscr.c
+          The (old, uucp-like) SCRIPT command
+
+   [100]ckudia.c
+          The DIAL command. Includes specific knowledge of many types of
+          modems.
+
+   Note that none of the above files is actually Unix-specific. Over time
+   they have proven to be portable among all platforms where C-Kermit is
+   built: Unix, VMS, AOS/VS, Amiga, OS-9, VOS, etc etc. Thus the third
+   letter should more properly be "c", but changing it would be too
+   confusing.
+
+   ck?con.c, ckucns.c
+          The CONNECT command. Terminal connection, and in some cases
+          (Macintosh, Windows) also terminal emulation. NOTE: As of
+          C-Kermit 7.0, there are two different CONNECT modules for UNIX:
+          [101]ckucon.c -- the traditional, portable, fork()-based version
+          -- and [102]ckucns.c, a new version that uses select() rather
+          than forks so it can handle encryption. ckucns.c is the
+          preferred version for Unix; ckucon.c is not likely to keep pace
+          with it in terms of upgrades, etc. However, since select() is
+          not portable to every platform, ckucon.c will be kept
+          indefinitely for those platforms that can't use ckucns.c. NOTE:
+          SunLink X.25 support is available only in ckucon.c.
+
+   ck_*.*, ckuat*.*
+          Modules having to do with authentication and encryption. Since
+          the relaxation of USA export laws, they are included with the
+          general source-code distribution. Secure C-Kermit binaries can
+          be built using special targets in the standard makefile.
+          However, secure prebuilt binaries may not be distributed.
+
+   For other implementations, the files may, and probably do, have
+   different names. For example, the Macintosh graphical user interface
+   filenames start with "ckm". Kermit 95 uses the ckucmd and ckuus*
+   modules, but has its own CONNECT command modules. And so on.
+
+   Here is a brief description of C-Kermit's "user interface interface",
+   from ckuusr.c. It is nowhere near complete; in particular, hundreds of
+   global variables are shared among the many modules. These should, some
+   day, be collected into classes or structures that can be passed around
+   as needed; not only for purity's sake, but also to allow for multiple
+   simultaneous communication sessions and or user interfaces. Our list of
+   things to do is endless, and reorganizing the source is almost always
+   at the bottom.
+
+   The ckuus*.c modules (like many of the ckc*.c modules) depend on the
+   existence of C library features like fopen, fgets, feof, (f)printf,
+   argv/argc, etc. Other functions that are likely to vary among operating
+   systems -- like setting terminal modes or interrupts -- are invoked via
+   calls to functions that are defined in the [103]Group E
+   platform-dependent modules, ck?[ft]io.c. The command line parser
+   processes any arguments found on the command line, as passed to main()
+   via argv/argc. The interactive parser uses the facilities of the cmd
+   package (developed for this program, but, in theory, usable by any
+   program). Any command parser may be substituted for this one. The only
+   requirements for the Kermit command parser are these:
+
+    1. Set parameters via global variables like duplex, speed, ttname,
+       etc. See [104]ckcmai.c for the declarations and descriptions of
+       these variables.
+    2. If a command can be executed without the use of Kermit protocol,
+       then execute the command directly and set the sstate (start state)
+       variable to 0. Examples include SET commands, local directory
+       listings, the CONNECT command.
+    3. If a command requires the Kermit protocol, set the following
+       variables:
+ sstate                             string data
+   'x' (enter server mode)            (none)
+   'r' (send a 'get' command)         cmarg, cmarg2
+   'v' (enter receive mode)           cmarg2
+   'g' (send a generic command)       cmarg
+   's' (send files)                   nfils, cmarg & cmarg2 OR cmlist
+   'c' (send a remote host command)   cmarg
+
+
+       cmlist is an array of pointers to strings.
+       cmarg, cmarg2 are pointers to strings.
+       nfils is an integer (hmmm, probably should be an unsigned long).
+
+        cmarg can be:
+                A filename string (possibly wild), or:
+                a pointer to a prefabricated generic command string, or:
+                a pointer to a host command string.
+
+        cmarg2 is:
+                The name to send a single file under, or:
+                the name under which to store an incoming file; must not
+                be wild.
+                If it's the name for receiving, a null value means to
+                store the file under the name it arrives with.
+
+        cmlist is:
+                A list of nonwild filenames, such as passed via argv.
+
+        nfils is an integer, interpreted as follows:
+                -1: filespec (possibly wild) in cmarg, must be expanded
+                internally.
+                0: send from stdin (standard input).
+                >0: number of files to send, from cmlist.
+
+   The screen() function is used to update the screen during file
+   transfer. The tlog() function writes to a transaction log (if TLOG is
+   defined). The debug() function writes to a debugging log (if DEBUG is
+   defined). The intmsg() and chkint() functions provide the user i/o for
+   interrupting file transfers.
+
+   [ [105]Contents ] [ [106]C-Kermit ] [ [107]Kermit Home ]
+
+4.E. Group E: Platform-Dependent I/O
+
+   Platform-dependent function definitions. All the Kermit modules,
+   including the command package, call upon these functions, which are
+   designed to provide system-independent primitives for controlling and
+   manipulating devices and files. For Unix, these functions are defined
+   in the files [108]ckufio.c (files), [109]ckutio.c (communications), and
+   [110]ckusig.c (signal handling).
+
+   For VMS, the files are [111]ckvfio.c, ckvtio.c, and [112]ckusig.c (VMS
+   can use the same signal handling routines as Unix). It doesn't really
+   matter what the files are called, except for Kermit distribution
+   purposes (grouping related files together alphabetically), only that
+   each function is provided with the name indicated, observes the same
+   calling and return conventions, and has the same type.
+
+   The Group E modules contain both functions and global variables that
+   are accessed by modules in the other groups. These are now described.
+
+   (By the way, I got this list by linking all the C-Kermit modules
+   together except ckutio and ckufio. These are the symbols that ld
+   reported as undefined. But that was a long time ago, probably circa
+   Version 6.)
+
+4.E.1. Global Variables
+
+   char *DELCMD;
+          Pointer to string containing command for deleting files.
+          Example: char *DELCMD = "rm -f "; (UNIX)
+          Example: char *DELCMD = "delete "; (VMS)
+          Note trailing space. Filename is concatenated to end of this
+          string. NOTE: DELCMD is used only in versions that do not
+          provide their own built-in DELETE command.
+
+   char *DIRCMD;
+          Pointer to string containing command for listing files when a
+          filespec is given.
+          Example: char *DIRCMD = "/bin/ls -l "; (UNIX)
+          Example: char *DIRCMD = "directory "; (VMS)
+          Note trailing space. Filename is concatenated to end of this
+          string. NOTE: DIRCMD is used only in versions that do not
+          provide their own built-in DIRECTORY command.
+
+   char *DIRCM2;
+          Pointer to string containing command for listing files when a
+          filespec is not given. (currently not used, handled in another
+          way.)
+          Example: char *DIRCMD2 = "/bin/ls -ld *";
+          NOTE: DIRCMD2 is used only in versions that do not provide their
+          own built-in DIRECTORY command.
+
+   char *PWDCMD;
+          Pointer to string containing command to display current
+          directory.
+          Example: char *PWDCMD = "pwd ";
+          NOTE: PWDCMD is used only in versions that do not provide their
+          own built-in PWD command.
+
+   char *SPACMD;
+          Pointer to command to display free disk space in current
+          device/directory.
+          Example: char *SPACMD = "df .";
+          NOTE: SPACMD is used only in versions that do not provide their
+          own built-in SPACE command.
+
+   char *SPACM2;
+          Pointer to command to display free disk space in another
+          device/directory.
+          Example: char *SPACM2 = "df ";
+          Note trailing space. Device or directory name is added to this
+          string. NOTE: SPACMD2 is used only in versions that do not
+          provide their own built-in SPACE command.
+
+   char *TYPCMD;
+          Pointer to command for displaying the contents of a file.
+          Example: char *TYPCMD = "cat ";
+          Note trailing space. Device or directory name is added to this
+          string. NOTE: TYPCMD is used only in versions that do not
+          provide their own built-in TYPE command.
+
+   char *WHOCMD;
+          Pointer to command for displaying logged-in users.
+          Example: char *WHOCMD = "who ";
+          Note trailing space. Specific user name may be added to this
+          string.
+
+   int backgrd = 0;
+          Flag for whether program is running in foreground (0) or
+          background (nonzero). Background operation implies that screen
+          output should not be done and that all errors should be fatal.
+
+   int ckxech;
+          Flag for who is to echo console typein:
+          1: The program (system is not echoing).
+          0: The OS, front end, terminal, etc (not this program).
+
+   char *ckxsys;
+          Pointer to string that names the computer and operating system.
+          Example: char *ckxsys = " NeXT Mach 1.0";
+          Tells what computer system ckxv applies to. In UNIX Kermit, this
+          variable is also used to print the program herald, and in the
+          SHOW VERSION command.
+
+   char *ckxv;
+          Pointer to version/edit info of ck?tio.c module.
+          Example: char *ckxv = "UNIX Communications Support, 6.0.169, 6
+          Sep 96";
+          Used by SHOW VERSION command.
+
+   char *ckzsys;
+          Like ckxsys, but briefer.
+          Example: char *ckzsys = " 4.3 BSD";
+          Tells what platform ckzv applies to. Used by the SHOW VERSION
+          command.
+
+   char *ckzv;
+          Pointer to version/edit info of ck?fio.c module.
+          Example: char *ckzv = "UNIX File support, 6.0.113, 6 Sep 96";
+          Used by SHOW VERSION command.
+
+   int dfflow;
+          Default flow control. 0 = none, 1 = Xon/Xoff, ... (see FLO_xxx
+          symbols in ckcdeb.h)
+          Set by Group E module. Used by [113]ckcmai.c to initialize flow
+          control variable.
+
+   int dfloc;
+          Default location. 0 = remote, 1 = local. Set by Group E module.
+          Used by ckcmai.c to initialize local variable. Used in various
+          places in the user interface.
+
+   int dfprty;
+          Default parity. 0 = none, 'e' = even, 'o' = odd, 'm' = mark, 's'
+          = space. Set by Group E module. Used by ckcmai.c to initialize
+          parity variable.
+
+   char *dftty;
+          Default communication device. Set by Group E module. Used in
+          many places. This variable should be initialized the the symbol
+          CTTNAM, which is defined in ckcdeb.h, e.g. as "/dev/tty" for
+          UNIX, "TT:" for VMS, etc. Example: char *dftty = CTTNAM;
+
+   char *mtchs[];
+          Array of string pointers to filenames that matched the most
+          recent wildcard match, i.e. the most recent call to zxpand().
+          Used (at least) by command parsing package for partial filename
+          completion.
+
+   int tilde_expand;
+          Flag for whether to attempt to expand leading tildes in
+          directory names (used in UNIX only, and then only when the
+          symbol DTILDE is defined.
+
+   int ttnproto;
+          The protocol being used to communicate over a network device.
+          Values are defined in ckcnet.h. Example: NP_TELNET is network
+          protocol "telnet".
+
+   int maxnam;
+          The maximum length for a filename, exclusive of any device or
+          directory information, in the format of the host operating
+          system.
+
+   int maxpath;
+          The maximum length for a fully specified filename, including
+          device designator, directory name, network node name, etc, in
+          the format of the host operating system, and including all
+          punctuation.
+
+   int ttyfd;
+          File descriptor of the communication device. -1 if there is no
+          open or usable connection, including when C-Kermit is in remote
+          mode. Since this is not implemented everywhere, references to it
+          are in #ifdef CK_TTYFD..#endif.
+
+   [ [114]Contents ] [ [115]C-Kermit ] [ [116]Kermit Home ]
+
+4.E.2. Functions
+
+   These are divided into three categories: file-related functions (B.1),
+   communication functions (B.2), and miscellaneous functions (B.3).
+
+4.E.2.1. File-Related Functions
+
+   In most implementations, these are collected together into a module
+   called ck?fio.c, where ? = "u" ([117]ckutio.c for Unix), "v"
+   ([118]ckvtio.c for VMS), [119]etc. To be totally platform-independent,
+   C-Kermit maintains its own file numbers, and provides the functions
+   described in this section to deal with the files associated with them.
+   The file numbers are referred to symbolically, and are defined as
+   follows in ckcker.h:
+
+  #define ZCTERM      0           /* Console terminal */
+  #define ZSTDIO      1           /* Standard input/output */
+  #define ZIFILE      2           /* Current input file for SEND command */
+  #define ZOFILE      3           /* Current output file for RECEIVE command */
+  #define ZDFILE      4           /* Current debugging log file */
+  #define ZTFILE      5           /* Current transaction log file */
+  #define ZPFILE      6           /* Current packet log file */
+  #define ZSFILE      7           /* Current session log file */
+  #define ZSYSFN      8           /* Input from a system function (pipe) */
+  #define ZRFILE      9           /* Local file for READ command */  (NEW)
+  #define ZWFILE     10           /* Local file for WRITE command */ (NEW)
+  #define ZMFILE     11           /* Auxilliary file for internal use */ (NEW)
+  #define ZNFILS     12           /* How many defined file numbers */
+
+   In the descriptions below, fn refers to a filename, and n refers to one
+   of these file numbers. Functions are of type int unless otherwise
+   noted, and are listed mostly alphabetically.
+
+   int
+          chkfn(n) int n;
+          Checks the file number n. Returns:
+           -1: File number n is out of range
+            0: n is in range, but file is not open
+            1: n in range and file is open
+
+   int
+          iswild(filspec) char *filespec;
+          Checks if the file specification is "wild", i.e. contains
+          metacharacters or other notations intended to match multiple
+          filenames. Returns:
+            0: not wild
+            1: wild.
+
+   int
+          isdir(string) char *string;
+          Checks if the string is the name of an existing directory. The
+          idea is to check whether the string can be "cd'd" to, so in some
+          cases (e.g. DOS) it might also indicate any file structured
+          device, such as a disk drive (like A:). Other nonzero returns
+          indicate system-dependent information; e.g. in VMS
+          isdir("[.FOO]") returns 1 but isdir("FOO.DIR;1") returns 2 to
+          indicate the directory-file name is in a format that needs
+          conversion before it can be combined with a filename. Returns:
+            0: not a directory (including any kind of error)
+            1: it is an existing directory
+
+   char *
+          zfcdat(name) char *name;
+          Returns modification (preferably, otherwise creation) date/time
+          of file whose name is given in the argument string. Return value
+          is a pointer to a string of the form yyyymmdd hh:mm:ss, for
+          example 19931231 23:59:59, which represents the local time (no
+          timezone or daylight savings time finagling required). Returns
+          the null string ("") on failure. The text pointed to by the
+          string pointer might be in a static buffer, and so should be
+          copied to a safe place by the caller before any subsequent calls
+          to this function.
+
+   struct zfnfp *
+          zfnqfp(fn, buflen, buf) char * fn; int buflen; char * buf;
+          Given the filename fn, the corresponding fully qualified,
+          absolute filename is placed into the buffer buf, whose length is
+          buflen. On failure returns a NULL pointer. On success returns a
+          pointer to a struct zfnfp containing pointers to the full
+          pathname and to just the filename, and an int giving the length
+          of the full pathname. All references to this function in
+          mainline code must be protected by #ifdef ZFNQFP..#endif,
+          because it is not present in all of the ck*fio.c modules. So if
+          you implement this function in a version that did not have it
+          before, be sure to add #define ZFNQFP in the appropriate spot in
+          ckcdeb.h or in the build-procedure CFLAGS.
+
+   int
+          zcmpfn(s1,s2) char * s2, * s2;
+          Compares two filenames to see if they refer to the same.
+          Internally, the arguments can be converted to fully qualified
+          pathnames, e.g. with zfnqfp(), realpath(), or somesuch. In Unix
+          or other systems where symbolic links exist, the link should be
+          resolved before making the comparison or looking at the inodes.
+          Returns:
+            0: Files are not identical.
+            1: Files are identical.
+
+   int
+          zfseek(pos) long pos;
+          Positions the input pointer on the current input file to the
+          given position. The pos argument is 0-based, the offset
+          (distance in bytes) from beginning of the file. Needed for
+          RESEND, PSEND, and other recovery operations. This function is
+          not necessarily possible on all systems, e.g. record-oriented
+          systems. It should only be used on binary files (i.e. files we
+          are sending in binary mode) and stream-oriented file systems.
+          Returns:
+           -1: on failure.
+            0: On success.
+
+   int
+          zchdir(dirnam) char *dirnam;
+          Changes current or default directory to the one given in dirnam.
+          Returns:
+            0: On failure.
+            1: on success.
+
+   long
+          zchki(fn) char *fn;
+          Check to see if file with name fn is a regular, readable,
+          existing file, suitable for Kermit to send -- not a directory,
+          not a symbolic link, etc. Returns:
+           -3: if file exists but is not accessible (e.g. read-protected);
+           -2: if file exists but is not of a readable type (e.g. a
+          directory);
+           -1: on error (e.g. file does not exist, or fn is garbage);
+          >=0: (length of file) if file exists and is readable.
+          Also see isdir(), zgetfs().
+
+   int
+          zchkpid(pid) unsigned long pid;
+          Returns:
+            1: If the given process ID (e.g. pid in UNIX) is valid and
+          active
+            0: otherwise.
+
+   long
+          zgetfs(fn) char *fn;
+          Gets the size of the given file, regardless of accessibility.
+          Used for directory listings. Unlike zchki(), should return the
+          size of any kind of file, even a directory. zgetfs() also should
+          serve as a mini "get file info" function that can be used until
+          we design a better one, by also setting some global variables:
+            int zgfs_link   = 1/0 = file is (not) a symbolic link.
+            int zgfs_dir    = 1/0 = file is (not) a directory.
+            char linkname[] = if zgfs_link != 0, name of file link points
+          to.
+          Returns:
+           -1: on error (e.g. file does not exist, or fn is garbage);
+          >=0: (length of file) if file exists and is readable.
+
+   int
+          zchko(fn) char *fn;
+          Checks to see if a file of the given name can be created.
+          Returns:
+           -1: if file cannot be created, or on any kind of error.
+            0: if file can be created.
+
+   int
+          zchkspa(fn,len) char *f; long len;
+          Checks to see if there is sufficient space to store the file
+          named fn, which is len bytes long. If you can't write a function
+          to do this, then just make a dummy that always returns 1; higher
+          level code will recover from disk-full errors. The receiving
+          Kermit uses this function to refuse an incoming file based on
+          its size, via the attribute mechanism. Returns:
+           -1: on error.
+            0: if there is not enough space.
+            1: if there is enough space.
+
+   int
+          zchin(n,c) int n; int *c;
+          Gets a character from file number n, return it in c (call with
+          &c). Returns:
+           -1: on failure, including EOF.
+            0: on success with character in c.
+
+   int
+          zchout(n,c) int n; char c;
+          Writes the character c to file number n. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          zclose(n) int n;
+          Closes file number n. Returns:
+           -1: on error.
+            1: on success.
+
+   int
+          zdelet(fn) char *name;
+          Attempts to delete (remove, erase) the named file. Returns:
+           -1: on error.
+            1: if file was deleted successfully.
+
+   char *
+          zgperm(char * f)
+          Returns a pointer to the system-dependent numeric
+          permissions/protection string for file f, or NULL upon failure.
+          Used if CK_PERMS is defined.
+
+   char *
+          ziperm(char * f)
+          Returns a pointer to the system-dependent symbolic
+          permissions/protection string for file f, or NULL upon failure.
+          Used if CK_PERMS is defined. Example: In UNIX zgperm(f) might
+          return "100770", but ziperm() might return "-rwxrwx---". In VMS,
+          zgperm() would return a hexadecimal string, but ziperm() would
+          return something like "(RWED,RWED,RE,)".
+
+   char *
+          zgtdir()
+          Returns a pointer to the name of the current directory, folder,
+          etc, or a NULL pointer if the current directory cannot be
+          determined. If possible, the directory specification should be
+          (a) fully specified, e.g. as a complete pathname, and (b) be
+          suitable for appending a filename. Thus, for example, Unix
+          directory names should end with '/'. VMS directory names should
+          look like DEV:[NAME] (rather than, say, NAME.DIR;1).
+
+   char *
+          zhome()
+          Returns a pointer to a string containing the user's home
+          directory, or NULL upon error. Should be formatted like zgtdir()
+          (q.v.).
+
+   int
+          zinfill()
+          Fill buffer from input file. This function is used by the macro
+          zminchar(), which is defined in ckcker.h. zminchar() manages its
+          own buffer, and calls zinfill() to fill it whenever it becomes
+          empty. It is used only for sending files, and reads characters
+          only from file number ZIFILE. zinfill() returns -1 upon end of
+          file, -2 upon fatal error, and -3 upon timeout (e.g. when
+          reading from a pipe); otherwise it returns the first character
+          from the buffer it just read.
+
+   int
+          zkself()
+          Kills the current job, session, process, etc, logs out,
+          disappears. Used by the Kermit server when it receives a BYE
+          command. On failure, returns -1. On success, does not return at
+          all! This function should not be called until all other steps
+          have been taken to close files, etc.
+
+   VOID
+          zstrip(fn,&fn2) char *fn1, **fn2;
+          Strips device and directory, etc, from file specification fn,
+          leaving only the filename (including "extension" or "filetype"
+          -- the part after the dot). For example DUA0:[PROGRAMS]OOFA.C;3
+          becomes OOFA.C, or /usr/fdc/oofa.c becomes oofa.c. Returns a
+          pointer to result in fn2.
+
+   int
+          zsetperm(char * file, unsigned int code)
+          Set permissions of file to given system-dependent code.   0: On
+          failure.
+            1: on success.
+
+   int
+          zsetroot(char * dir)
+          Sets the root for the user's file access, like Unix chroot(),
+          but does not require privilege. In Unix, this must be
+          implemented entirely by Kermit's own file access routines.
+          Returns:
+            1: Success
+           -1: Invalid argument
+           -2:
+           -3: Internal error
+           -4: Access to given directory denied
+           -5: New root not within old root
+
+   int
+          zinroot(char * file)
+          If no root is set (zsetroot()), returns 1.
+          Otherwise, if given file is in the root, returns 1.
+          Otherwise, returns 0.
+
+   VOID
+          zltor(fn,fn2) char *fn1, *fn2;
+          Local-To-Remote filename translation. OBSOLETE: replaced by
+          nzltor() (q.v.). Translates the local filename fn into a format
+          suitable for transmission to an arbitrary type of computer, and
+          copies the result into the buffer pointed to by fn2. Translation
+          may involve (a) stripping the device and/or directory/path name,
+          (b) converting lowercase to uppercase, (c) removing spaces and
+          strange characters, or converting them to some innocuous
+          alphabetic character like X, (d) discarding or converting extra
+          periods (there should not be more than one). Does its best.
+          Returns no value. name2 is a pointer to a buffer, furnished by
+          the caller, into which zltor() writes the resulting name. No
+          length checking is done.
+
+   #ifdef NZLTOR
+          VOID
+          nzltor(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+          convert,pathnames,max;
+          Replaces zltor(). This new version handles pathnames and checks
+          length. fn1 and fn2 are as in zltor(). This version is called
+          unconditionally for each file, rather than only when filename
+          conversion is enabled. Pathnames can have the following values:
+
+            PATH_OFF: Pathname, if any, is to be stripped
+            PATH_REL: The relative pathname is to be included
+            PATH_ABS: The full pathname is to be included
+
+          After handling pathnames, conversion is done to the result as in
+          the zltor() description if convert != 0; if relative or absolute
+          pathnames are included, they are converted to UNIX format, i.e.
+          with slash (/) as the directory separator. The max parameter
+          specifies the maximum size of fn2. If convert > 0, the regular
+          conversions are done; if convert < 0, minimal conversions are
+          done (we skip uppercasing the letters, we allow more than one
+          period, etc; this can be used when we know our partner is UNIX
+          or similar).
+
+   #endif /* NZLTOR */
+
+   int
+          nzxpand(fn,flags) char *fn; int flags;
+          Replaces zxpand(), which is obsolete as of C-Kermit 7.0.
+          Call with:
+            fn = Pointer to filename or pattern.
+            flags = option bits:
+              flags & ZX_FILONLY  Match regular files
+              flags & ZX_DIRONLY  Match directories
+              flags & ZX_RECURSE  Descend through directory tree
+              flags & ZX_MATCHDOT Match "dot files"
+              flags & ZX_NOBACKUP Don't match "backup files"
+              flags & ZX_NOLINKS  Don't follow symlinks.
+
+          Returns the number of files that match fn, with data structures
+          set up so the first file (if any) will be returned by the next
+          znext() call. If ZX_FILONLY and ZX_DIRONLY are both set, or
+          neither one is set, files and directories are matched. Notes:
+
+         1. It is essential that the number returned by nzxpand() reflect
+            the actual number of filenames that will be returned by
+            znext() calls. In other words:
+  for (n = nzxpand(string,flags); n > 0; n--) {
+      znext(buf);
+      printf("%s\n", buf);
+  }
+
+            should print all the file names; no more, no less.
+         2. In UNIX, DOS, OS-9, etc, where directories contain entries for
+            themselves (.) and the superior directory (..), these should
+            NOT be included in the list under any circumstances, including
+            when ZX_MATCHDOT is set.
+         3. Additional option bits might be added in the future, e.g. for
+            sorting (sort by date/name/size, reverse/ascending, etc).
+            Currently this is done only in higher level code (through a
+            hack in which the nzxpand() exports its filename array, which
+            is not portable because not all OS's can use this mechanism).
+
+   int
+          zmail(addr,fn) char *addr, fn;
+          Send the local, existing file fn as e-mail to the address addr.
+          Returns:
+            0: on success
+            2: if mail delivered but temp file can't be deleted
+           -2: if mail can't be delivered
+
+   int
+          zmkdir(path) char *path;
+          The path can be a file specification that might contain
+          directory information, in which the filename is expected to be
+          included, or an unambiguous directory specification (e.g. in
+          UNIX it must end with "/"). This routine attempts to create any
+          directories in the given path that don't already exist. Returns
+          0 or greater success: no directories needed creation, or else
+          all directories that needed creation were created successfully;
+          the return code is the number of directories that were created.
+          Returns -1 on failure to create any of the needed directories.
+
+   int
+          zrmdir(path) char *path;
+          Attempts to remove the given directory. Returns 0 on success, -1
+          on failure. The detailed semantics are open -- should it fail if
+          the directory contains any files or subdirectories, etc. It is
+          probably best for this routine to behave in whatever manner is
+          customary on the underlying platform; e.g. in UNIX, VMS, DOS,
+          etc, where directories can not be removed unless they are empty.
+
+   VOID
+          znewn(fn,s) char *fn, **s;
+          Transforms the name fn into a filename that is guaranteed to be
+          unique. If the file fn does not exist, then the new name is the
+          same as fn; Otherwise, it's different. this function does its
+          best, returns no value. New name is created in caller's space.
+          Call like this: znewn(old,&new);. The second parameter is a
+          pointer to the new name. This pointer is set by znewn() to point
+          to a static string in its own space, so be sure to the result to
+          a safe place before calling this function again.
+
+   int
+          znext(fn) char *fn;
+          Copies the next file name from a file list created by zxpand()
+          into the string pointed to by fn (see zxpand). If no more files,
+          then the null string is placed there. Returns 0 if there are no
+          more filenames, with 0th element the array pointed to by fn set
+          to NUL. If there is a filename, it is stored in the array
+          pointed to by fn and a positive number is returned. NOTE: This
+          is a change from earlier definitions of this function
+          (pre-1999), which returned the number of files remaining; thus 0
+          was the return value when returning the final file. However, no
+          mainline code ever depended on the return value, so this change
+          should be safe.
+
+   int
+          zopeni(n,fn) int n; char *fn;
+          Opens the file named fn for input as file number n. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          zopeno(n,fn,zz,fcb) int n; char *name; struct zattr *zz; struct
+          filinfo *fcb;
+          Attempts to open the named file for output as file number n. zz
+          is a Kermit file attribute structure as defined in ckcdeb.h,
+          containing various information about the file, including its
+          size, creation date, and so forth. This function should attempt
+          to honor as many of these as possible. fcb is a "file control
+          block" in the traditional sense, defined in ckcdeb.h, containing
+          information relevant to complicated file systems like VMS (RMS),
+          IBM MVS, etc, like blocksize, record length, organization,
+          record format, carriage control, etc. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          zoutdump()
+          Dumps a file output buffer. Used with the macro zmchout()
+          defined in ckcker.h. Used only with file number ZOFILE, i.e. the
+          file that is being received by Kermit during file transfer.
+          Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zprint(p,fn) char *p, *f;
+          Prints the file with name fn on a local printer, with options p.
+          Returns:
+            0: on success
+            3: if file sent to printer but can't be deleted
+           -3: if file can't be printed
+
+   int
+          zrename(fn,fn2) char *fn, *fn2;
+          Changes the name of file fn to fn2. If fn2 is the name of an
+          existing directory, or a file-structured device, then file fn is
+          moved to that directory or device, keeping its original name. If
+          fn2 lacks a directory separator when passed to this function, an
+          appropriate one is supplied. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zcopy(source,dest) char * source, * dest;
+          Copies the source file to the destination. One file only. No
+          wildcards. The destination string may be a filename or a
+          directory name. Returns:
+            0: on success.
+           <0: on failure:
+            -2: source file is not a regular file.
+            -3: source file not found.
+            -4: permission denied.
+            -5: source and destination are the same file.
+            -6: i/o error.
+            -1: other error.
+
+   char *
+          zlocaltime(char *)
+          Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time. Returns
+          pointer to local date-time string "yyyymmdd hh:mm:ss" on
+          success, NULL on failure.
+
+   VOID
+          zrtol(fn,fn2) char *fn, *fn2;
+          Remote-To-Local filename translation. OBSOLETE: replaced by
+          nzrtol(). Translates a "standard" filename to a local filename.
+          For example, in Unix this function might convert an
+          all-uppercase name to lowercase, but leave lower- or mix-case
+          names alone. Does its best, returns no value. New name is in
+          string pointed to by fn2. No length checking is done.
+
+   #ifdef NZLTOR
+   int
+          nzrtol(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+          convert,pathnames,max;
+          Replaces zrtol. Like zrtol but handles pathnames and checks
+          length. See nzltor for detailed description of parameters.
+
+   #endif /* NZLTOR */
+
+   int
+          zsattr(xx) struct zattr *xx;
+          Fills in a Kermit file attribute structure for the file which is
+          to be sent, namely the currently open ZIFILE. Note that this is
+          not a very good design, but we're stuck with it. Callers must
+          ensure that zsattr() is called only on real files, not on pipes,
+          internally generated file-like objects such as server REMOTE
+          command responses, etc. Returns:
+           -1: on failure.
+            0: on success with the structure filled in.
+          If any string member is null, it should be ignored by the
+          caller.
+          If any numeric member is -1, it should be ignored by the caller.
+
+   int
+          zshcmd(s) char *s;
+          s contains to pointer to a command to be executed by the host
+          computer's shell, command parser, or operating system. If the
+          system allows the user to choose from a variety of command
+          processors (shells), then this function should employ the user's
+          preferred shell. If possible, the user's job (environment,
+          process, etc) should be set up to catch keyboard interruption
+          signals to allow the user to halt the system command and return
+          to Kermit. The command must run in ordinary, unprivileged user
+          mode. If possible, this function should return -1 on failure to
+          start the command, or else it should return 1 if the command
+          succeeded and 0 if it failed.
+
+   int
+          pexitstatus
+          zshcmd() and zsyscmd() should set this to the command's actual
+          exit status code if possible.
+
+   int
+          zsyscmd(s) char *s;
+          s contains to pointer to a command to be executed by the host
+          computer's shell, command parser, or operating system. If the
+          system allows the user to choose from a variety of command
+          processors (shells), then this function should employ the system
+          standard shell (e.g. /bin/sh for Unix), so that the results will
+          always be the same for everybody. If possible, the user's job
+          (environment, process, etc) should be set up to catch keyboard
+          interruption signals to allow the user to halt the system
+          command and return to Kermit. The command must run in ordinary,
+          unprivileged user mode. If possible, this function should return
+          -1 on failure to start the command, or else it should return 1
+          if the command succeeded and 0 if it failed.
+
+   VOID
+          z_exec(s,args) char * s; char * args[];
+          This one executes the command s (which is searched for using the
+          system's normal searching mechanism, such as PATH in UNIX), with
+          the given argument vector, which follows the conventions of UNIX
+          argv[]: the name of the command pointed to by element 0, the
+          first arg by element 1, and so on. A null args[] pointer
+          indicates the end of the arugment list. All open files must
+          remain open so the exec'd process can use them. Returns only if
+          unsuccessful.
+
+   int
+          zsinl(n,s,x) int n, x; char *s;
+          Reads a line from file number n. Writes the line into the
+          address s provided by the caller. Writing terminates when
+          newline is read, but with newline discarded. Writing also
+          terminates upon EOF or if length x is exhausted. Returns:
+           -1: on EOF or error.
+            0: on success.
+
+   int
+          zsout(n,s) int n; char *s;
+          Writes the string s out to file number n. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zsoutl(n,s) int n; char *s;
+          Writes the string s out to file number n and adds a line
+          (record) terminator (boundary) appropriate for the system and
+          the file format. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zsoutx(n,s,x) int n, x; char *s;
+          Writes exactly x characters from string s to file number n. If s
+          has fewer than x characters, then the entire string s is
+          written. Returns:
+           -1: on failure.
+          >= 0: on success, the number of characters actually written.
+
+   int
+          zstime(fn,yy,x) char *fn; struct zattr *yy; int x;
+          Sets the creation date (and other attributes) of an existing
+          file, or compares a file's creation date with a given date. Call
+          with:
+
+   fn: pointer to name of existing file.
+   yy: Pointer to a Kermit file attribute structure in which yy->date.val
+   is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00, which
+   is to be used for setting or comparing the file date. Other attributes
+   in the struct can also be set, such as the protection/permission (See
+   [120]Appendix I), when it makes sense (e.g. "yy->lprotect.val" can be
+   set if the remote system ID matches the local one).
+    x: A function code: 0 means to set the file's creation date as given.
+   1 means compare the date from the yy struct with the file's date.
+
+          Returns:
+           -1: on any kind of error.
+            0: if x is 0 and the file date was set successfully.
+            0: if x is 1 and date from attribute structure > file creation
+          date.
+            1: if x is 1 and date from attribute structure <= file
+          creation date.
+
+   VOID
+          zstrip(name,name2) char *name, **name2;
+          Strips pathname from filename "name". Constructs the resulting
+          string in a static buffer in its own space and returns a pointer
+          to it in name2. Also strips device name, file version numbers,
+          and other "non-name" material.
+
+   int
+          zxcmd(n,s) char *s;
+          Runs a system command so its output can be accessed as if it
+          were file n. The command is run in ordinary, unprivileged user
+          mode.
+          If n is ZSTDIO or ZCTERM, returns -1.
+          If n is ZIFILE or ZRFILE, then Kermit reads from the command,
+          otherwise Kermit writes to the command.
+          Returns 0 on error, 1 on success.
+
+   int
+          zxpand(fn) char *fn;
+          OBSOLETE: Replaced by nzxpand(), q.v.
+
+   #ifdef ZXREWIND
+   int
+          zxrewind()
+          Returns the number of files returned by the most recent
+          nzxpand() call, and resets the list to the beginning so the next
+          znext() call returns the first file. Returns -1 if zxpand has
+          not yet been called. If this function is available, ZXREWIND
+          should be defined; otherwise it should not be referenced.
+
+   #endif /* ZXREWIND */
+
+   int
+          xsystem(cmd) char *cmd;
+          Executes the system command without redirecting any of its i/o,
+          similar (well, identical) to system() in Unix. But before
+          passing the command to the system, xsystem() ensures that all
+          privileges are turned off, so that the system command executes
+          in ordinary unprivileged user mode. If possible, xsystem()
+          returns the return code of the command that was executed.
+
+4.E.2.2. IKSD Variables and Functions
+
+   These must be implemented in any C-Kermit version that is to be
+   installed as an Internet Kermit Service Daemon (IKSD). IKSD is expected
+   to be started by the Internet Daemon (e.g. inetd) with its standard i/o
+   redirected to the incoming connection.
+
+   int ckxanon;
+          Nonzero if anonymous logins allowed.
+
+   extern int inserver;
+          Nonzero if started in IKSD mode.
+
+   extern int isguest;
+          Nonzero if IKSD and user logged in anonymously.
+
+   extern char * homdir;
+          Pointer to user's home directory.
+
+   extern char * anonroot;
+          Pointer to file-system root for anonymous users.
+
+   Existing functions must make "if (inserver && isguest)" checks for
+   actions that would not be legal for guests: zdelete(), zrmdir(),
+   zprint(), zmail(), etc.
+
+   int
+          zvuser(name) char * name;
+          Verifies that user "name" exists and is allowed to log in. If
+          the name is "ftp" or "anonymous" and ckxanon != 0, a guest login
+          is set up. Returns 0 if user not allowed to log in, nonzero if
+          user may log in.
+
+   int
+          zvpass(string) char * string;
+          Verifies password of the user from the most recent zvuser()
+          call. Returns nonzero if password is valid for user, 0 if it
+          isn't. Makes any appropriate system log entries (IKSD logins,
+          failed login attempts, etc). If password is valid, logs the user
+          in as herself (if real user), or sets up restricted anonymous
+          access if user is guest (e.g. changes file-system root to
+          anonroot and sets isguest = 1).
+
+   VOID
+          zsyslog()
+          Begins any desired system logging of an IKSD session.
+
+   VOID
+          zvlogout()
+          Terminates an IKSD session. In most cases this is simply a
+          wrapper for exit() or doexit(), with some system logging added.
+
+4.E.2.3. Privilege Functions
+
+   These functions are used by C-Kermit to adapt itself to operating
+   systems where the program can be made to run in a "privileged" mode,
+   e.g. setuid or setgid in Unix. C-Kermit should NOT read and write files
+   or start subprocesses as a privileged program. This would present a
+   serious threat to system security. The security package has been
+   installed to prevent such security breaches by turning off the
+   program's special privileges at all times except when they are needed.
+
+   In UNIX, the only need Kermit has for privileged status is access to
+   the UUCP lockfile directory, in order to read, create, and destroy
+   lockfiles, and to open communication devices that are normally
+   protected against the user (see the [121]Unix C-Kermit Installation
+   Instructions for discussion). Therefore, privileges should only be
+   enabled for these operations and disabled at all other times. This
+   relieves the programmer of the responsibility of putting expensive and
+   unreliable access checks around every file access and subprocess
+   creation.
+
+   Strictly speaking, these functions are not required in all C-Kermit
+   implementations, because their use (so far, at least) is internal to
+   the Group E modules. However, they should be included in all C-Kermit
+   implementations for operating systems that support the notion of a
+   privileged program (UNIX, RSTS/E, what others?).
+
+   int
+          priv_ini()
+          Determine whether the program is running in privileged status.
+          If so, turn off the privileges, in such a way that they can be
+          turned on again when needed. Called from sysinit() at program
+          startup time. Returns:
+            0 on success
+            nonzero on failure, in which case the program should halt
+          immediately.
+
+   int
+          priv_on()
+          If the program is not privileged, this function does nothing. If
+          the program is privileged, this function returns it to
+          privileged status. priv_ini() must have been called first.
+          Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_off()
+          Turns privileges off (if they are on) in such a way that they
+          can be turned back on again. Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_can()
+          Turns privileges off in such a way that they cannot be turned
+          back on. Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_chk()
+          Attempts to turns privileges off in such a way that they can be
+          turned on again later. Then checks to make sure that they were
+          really turned off. If they were not really turned off, then they
+          are cancelled permanently. Returns:
+            0 on success
+            nonzero on failure
+
+4.E.2.4. Console-Related Functions
+
+   These relate to the program's "console", or controlling terminal, i.e.
+   the terminal that the user is logged in on and types commands at, or on
+   a PC or workstation, the actual keyboard and screen.
+
+   int
+          conbin(esc) char esc;
+          Puts the console into "binary" mode, so that Kermit's command
+          parser can control echoing and other treatment of characters
+          that the user types. esc is the character that will be used to
+          get Kermit's attention during packet mode; puts this in a global
+          place. Sets the ckxech variable. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          concb(esc) char esc;
+          Put console in "cbreak" (single-character wakeup) mode. That is,
+          ensure that each console character is available to the program
+          immediately when the user types it. Otherwise just like
+          conbin(). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          conchk()
+          Returns a number, 0 or greater, the number of characters waiting
+          to be read from the console, i.e. the number of characters that
+          the user has typed that have not been read yet by Kermit.
+
+   long
+          congspd();
+          Returns the speed ("baud rate") of the controlling terminal, if
+          known, otherwise -1L.
+
+   int
+          congks(timo) int timo;
+          Get Keyboard Scancode. Reads a keyboard scan code from the
+          physical console keyboard. If the timo parameter is greater than
+          zero, then times out and returns -2 if no character appears
+          within the given number of seconds. Upon any other kind of
+          error, returns -1. Upon success returns a scan code, which may
+          be any positive integer. For situations where scan codes cannot
+          be read (for example, when an ASCII terminal is used as the
+          job's controlling terminal), this function is identical to
+          coninc(), i.e. it returns an 8-bit character value. congks() is
+          for use with workstations whose keyboards have Alternate,
+          Command, Option, and similar modifier keys, and Function keys
+          that generate codes greater than 255.
+
+   int
+          congm()
+          Console get modes. Gets the current console terminal modes and
+          saves them so that conres() can restore them later. Returns 1 if
+          it got the modes OK, 0 if it did nothing (e.g. because Kermit is
+          not connected with any terminal), -1 on error.
+
+   int
+          coninc(timo) int timo;
+          Console Input Character. Reads a character from the console. If
+          the timo parameter is greater than zero, then coninc() times out
+          and returns -2 if no character appears within the given number
+          of seconds. Upon any other kind of error, returns -1. Upon
+          success, returns the character itself, with a value in the range
+          0-255 decimal.
+
+   VOID
+          conint(f,s) SIGTYP (*f)(), (*s)();
+          Sets the console to generate an interrupt if the user types a
+          keyboard interrupt character, and to transfer control the
+          signal-handling function f. For systems with job control, s is
+          the address of the function that suspends the job. Sets the
+          global variable "backgrd" to zero if Kermit is running in the
+          foreground, and to nonzero if Kermit is running in the
+          background. See ckcdeb.h for the definition of SIGTYP. No return
+          value.
+
+   VOID
+          connoi()
+          Console no interrupts. Disable keyboard interrupts on the
+          console. No return value.
+
+   int
+          conoc(c) char c;
+          Writes character c to the console terminal. Returns:
+          0 on failure, 1 on success.
+
+   int
+          conol(s) char *s;
+          Writes string s to the console. Returns -1 on error, 0 or
+          greater on success.
+
+   int
+          conola(s) char *s[]; {
+          Writes an array of strings to the console. Returns -1 on error,
+          0 or greater on success.
+
+   int
+          conoll(s) char *s;
+          Writes string s to the console, followed by the necessary line
+          termination characters to put the console cursor at the
+          beginning of the next line. Returns -1 on error, 0 or greater on
+          success.
+
+   int
+          conres()
+          Restores the console terminal to the modes obtained by congm().
+          Returns: -1 on error, 0 on success.
+
+   int
+          conxo(x,s) int x; char *s;
+          Write x characters from string s to the console. Returns 0 or
+          greater on success, -1 on error.
+
+   char *
+          conkbg();
+          Returns a pointer to the designator of the console keyboard
+          type. For example, on a PC, this function would return "88",
+          "101", etc. Upon failure, returns a pointer to the empty string.
+
+4.E.2.5. Communications Functions
+
+   The communication device is the device used for terminal emulation and
+   file transfer. It may or may not be the same device as the console, and
+   it may or may not be a terminal (serial-port) device; it could also be
+   a network connection. For brevity, the communication device is referred
+   to here as the "tty". When the communication device is the same as the
+   console device, Kermit is said to be in remote mode. When the two
+   devices are different, Kermit is in local mode.
+
+   int
+          ttchk()
+          Returns the number of characters that have arrived at the
+          communication device but have not yet been read by ttinc(),
+          ttinl(), and friends. If communication input is buffered (and it
+          should be), this is the sum of the number of unread characters
+          in Kermit's buffer PLUS the number of unread characters in the
+          operating system's internal buffer. The call must be
+          nondestructive and nonblocking, and as inexpensive as possible.
+          Returns:
+            0: or greater on success,
+            0: in case of internal error,
+           -1: or less when it determines the connection has been broken,
+          or there is no connection.
+
+          That is, a negative return from ttchk() should reliably indicate
+          that there is no usable connection. Furthermore, ttchk() should
+          be callable at any time to see if the connection is open. When
+          the connection is open, every effort must be made to ensure that
+          ttchk returns an accurate number of characters waiting to be
+          read, rather than just 0 (no characters) or 1 (1 or more
+          characters), as would be the case when we use select(). This
+          aspect of ttchk's operation is critical to successful operation
+          of sliding windows and streaming, but "nondestructive buffer
+          peeking" is an obscure operating system feature, and so when it
+          is not available, we have to do it ourselves by managing our own
+          internal buffer at a level below ttinc(), ttinl(), etc, as in
+          the UNIX version (non-FIONREAD case).
+
+          An external global variable, clsondisc, if nonzero, means that
+          if a serial connection drops (carrier on-to-off transition
+          detected by ttchk()), the device should be closed and released
+          automatically.
+
+   int
+          ttclos()
+          Closes the communication device (tty or network). If there were
+          any kind of exclusive access locks connected with the tty, these
+          are released. If the tty has a modem connection, it is hung up.
+          For true tty devices, the original tty device modes are
+          restored. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          ttflui()
+          Flush communications input buffer. If any characters have
+          arrived but have not yet been read, discard these characters. If
+          communications input is buffered by Kermit (and it should be),
+          this function flushes Kermit's buffer as well as the operating
+          system's internal input buffer. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          ttfluo()
+          Flush tty output buffer. If any characters have been written but
+          not actually transmitted (e.g. because the system has been
+          flow-controlled), remove them from the system's output buffer.
+          (Note, this function is not actually used, but it is recommended
+          that all C-Kermit programmers add it for future use, even if it
+          is only a dummy function that returns 0 always.)
+
+   int
+          ttgmdm()
+          Looks for the modem signals CTS, DSR, and CTS, and returns those
+          that are on in as its return value, in a bit mask as described
+          for ttwmdm, in which a bit is on (1) or off (0) according to
+          whether the corresponding signal is on (asserted) or off (not
+          asserted). Return values:
+           -3: Not implemented
+           -2: if the line does not have modem control
+           -1: on error
+          >=0: on success, with bit mask containing the modem signals.
+
+   long
+          ttgspd()
+          Returns the current tty speed in BITS (not CHARACTERS) per
+          second, or -1 if it is not known or if the tty is really a
+          network, or upon any kind of error. On success, the speed
+          returned is the actual number of bits per second, like 1200,
+          9600, 19200, etc.
+
+   int
+          ttgwsiz()
+          Get terminal window size. Returns -1 on error, 0 if the window
+          size can't be obtained, 1 if the window size has been
+          successfully obtained. Upon success, the external global
+          variables tt_rows and tt_cols are set to the number of screen
+          rows and number of screen columns, respectively. As this
+          function is not implemented in all ck*tio.c modules, calls to it
+          must be wrapped in #ifdef CK_TTGWSIZ..#endif. NOTE: This
+          function must be available to use the TELNET NAWS feature
+          (Negotiate About Window Size) as well as Rlogin.
+
+   int
+          tthang()
+          Hang up the current tty device. For real tty devices, turn off
+          DTR for about 1/3-1/2 second (or other length of time, depending
+          on the system). If the tty is really a network connection, close
+          it. Returns:
+           -1: on failure.
+            0: if it does not even try to hang up.
+            1: if it believes it hung up successfully.
+
+   VOID
+          ttimoff()
+          Turns off all pending timer interrupts.
+
+   int
+          ttinc(timo) int timo; (function is old, return codes are new)
+          Reads one character from the communication device. If timo is
+          greater than zero, wait the given number of seconds and then
+          time out if no character arrives, otherwise wait forever for a
+          character. Returns:
+           -3: internal error (e.g. tty modes set wrong)
+           -2: communications disconnect
+           -1: timeout or other error
+          >=0: the character that was read.
+          It is HIGHLY RECOMMENDED that ttinc() be internally buffered so
+          that calls to it are relatively inexpensive. If it is possible
+          to to implement ttinc() as a macro, all the better, for example
+          something like:
+
+  #define ttinc(t) ( (--txbufn >= 0) ? txbuf[ttbufp++] : txbufr(t) )
+
+          (see description of txbufr() below)
+
+   int
+          ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR
+          *dest, eol, start;
+          ttinl() is Kermit's packet reader. Reads a packet from the
+          communications device, or up to max characters, whichever occurs
+          first. A line is a string of characters starting with the start
+          character up to and including the character given in eol or
+          until the length is exhausted, or, if turn != 0, until the line
+          turnaround character (turn) is read. If turn is 0, ttinl()
+          *should* use the packet length field to detect the end, to allow
+          for the possibility that the eol character appears unprefixed in
+          the packet data. (The turnaround character is for half-duplex
+          linemode connections.)
+
+          If timo is greater than zero, ttinl() times out if the eol
+          character is not encountered within the given number of seconds
+          and returns -1.
+
+          The characters that were input are copied into "dest" with their
+          parity bits stripped if parity is not none. The first character
+          copied into dest should be the start character, and the last
+          should be the final character of the packet (the last block
+          check character). ttinl() should also absorb and discard the eol
+          and turn characters, and any other characters that are waiting
+          to be read, up until the next start character, so that
+          subsequent calls to ttchk() will not succeed simply because
+          there are some terminators still sitting in the buffer that
+          ttinl() didn't read. This operation, if performed, MUST NOT
+          BLOCK (so if it can't be performed in a guaranteed nonblocking
+          way, don't do it).
+
+          On success, ttinl() returns the number of characters read.
+          Optionally, ttinl() can sense the parity of incoming packets. If
+          it does this, then it should set the global variable ttprty
+          accordingly. ttinl() should be coded to be as efficient as
+          possible, since it is at the "inner loop" of packet reception.
+          ttinl() returns:
+           -1: Timeout or other possibly correctable error.
+           -2: Interrupted from keyboard.
+           -3: Uncorrectable i/o error -- connection lost, configuration
+          problem, etc.
+          >=0: on success, the number of characters that were actually
+          read and placed in the dest buffer, not counting the trailing
+          null.
+
+   int
+          ttoc(c) char c;
+          Outputs the character c to the communication line. If the
+          operation fails to complete within two seconds, this function
+          returns -1. Otherwise it returns the number of characters
+          actually written to the tty (0 or 1). This function should only
+          be used for interactive, character-mode operations, like
+          terminal connection, script execution, dialer i/o, where the
+          overhead of the signals and alarms does not create a bottleneck.
+          (THIS DESCRIPTION NEEDS IMPROVEMENT -- If the operation fails
+          within a "certain amount of time"... which might be dependent on
+          the communication method, speed, etc. In particular,
+          flow-control deadlocks must be accounted for and broken out of
+          to prevent the program from hanging indefinitely, etc.)
+
+   int
+          ttol(s,n) int n; char *s;
+          Kermit's packet writer. Writes the n characters of the string
+          pointed to to by s. NOTE: It is ttol's responsibility to write
+          ALL of the characters, not just some of them. Returns:
+           -1: on a possibly correctable error (so it can be retried).
+           -3: on a fatal error, e.g. connection lost.
+          >=0: on success, the actual number of characters written (the
+          specific number is not actually used for anything).
+
+   int
+          ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem,
+          timo;
+          Opens a tty device, if it is not already open. ttopen must check
+          to make sure the SAME device is not already open; if it is,
+          ttopen returns successfully without doing anything. If a
+          DIFFERENT device is currently open, ttopen() must call ttclos()
+          to close it before opening the new one.
+
+        Parameters:
+
+              ttname:
+                      character string - device name or network host name.
+
+              lcl:
+                      If called with lcl < 0, sets value of lcl as
+                      follows:
+                      0: the terminal named by ttname is the job's
+                      controlling terminal.
+                      1: the terminal named by ttname is not the job's
+                      controlling terminal.
+                      If the device is already open, or if the requested
+                      device can't be opened, then lcl remains (and is
+                      returned as) -1.
+
+              modem:
+                      Less than zero: this is the negative of the network
+                      type, and ttname is a network host name. Network
+                      types (from [122]ckcnet.h:
+
+  NET_TCPB 1   TCP/IP Berkeley (socket)  (implemented in [123]ckutio.c)
+  NET_TCPA 2   TCP/IP AT&T (streams)     (not yet implemented)
+  NET_DEC  3   DECnet                    (not yet implemented)
+
+                      Zero or greater: ttname is a terminal device name.
+                      Zero means a direct connection (don't use modem
+                      signals). Positive means use modem signals depending
+                      on the current setting of ttcarr (see ttscarr()).
+
+              timo:
+                      > 0: number of seconds to wait for open() to return
+                      before timing out.
+                      <=0: no timer, wait forever (e.g. for incoming
+                      call).
+                      For real tty devices, ttopen() attempts to gain
+                      exclusive access to the tty device, for example in
+                      UNIX by creating a "lockfile" (in other operating
+                      systems, like VMS, exclusive access probably
+                      requires no special action).
+
+        Side effects:
+                Copies its arguments and the tty file descriptor to global
+                variables that are available to the other tty-related
+                functions, with the lcl value altered as described above.
+                Gets all parameters and settings associated with the line
+                and puts them in a global area, so that they can be
+                restored by ttres(), e.g. when the device is closed.
+
+        Returns:
+                  0: on success
+                 -5: if device is in use
+                 -4: if access to device is denied
+                 -3: if access to lock mechanism denied
+                 -2: upon timeout waiting for device to open
+                 -1: on other error
+
+   int
+          ttpkt(speed,flow,parity) long speed; int flow, parity;
+          Puts the currently open tty device into the appropriate modes
+          for transmitting and receiving Kermit packets.
+
+        Arguments:
+
+              speed:
+                      if speed > -1, and the device is a true tty device,
+                      and Kermit is in local mode, ttpkt also sets the
+                      speed.
+
+              flow:
+                      if in the range 0-3, ttpkt selects the corresponding
+                      type of flow control. Currently 0 is defined as no
+                      flow control, 1 is Xon/Xoff, and no other types are
+                      defined. If (and this is a horrible hack, but it
+                      goes back many years and will be hard to eradicate)
+                      flow is 4, then the appropriate tty modes are set
+                      for modem dialing, a special case in which we talk
+                      to a modem-controlled line without requiring
+                      carrier. If flow is 5, then we require carrier.
+
+              parity:
+                      This is simply copied into a global variable so that
+                      other functions (like ttinl, ttinc, etc) can use it.
+
+        Side effects:
+                Copies its arguments to global variables, flushes the
+                terminal device input buffer.
+
+        Returns:
+                 -1: on error.
+                  0: on success.
+
+   int
+          ttsetflow(int)
+          Enables the given type of flow control on the open serial
+          communications device immediately. Arguments are the FLO_xxx
+          values from ckcdeb.h, except FLO_DIAL, FLO_DIAX, or FLO_AUTO,
+          which are not actual flow-control types. Returns 0 on success,
+          -1 on failure.
+
+   #ifdef TTSPDLIST
+   long *
+          ttspdlist()
+          Returns a pointer to an array of longs, or NULL on failure. On
+          success, element 0 of the array contains number, n, indicating
+          how many follow. Elements 1-n are serial speeds, expressed in
+          bits per second, that are legal on this platform. The user
+          interface may use this list to construct a menu, keyword table,
+          etc.
+
+   #endif /* TTSPDLIST */
+
+   int
+          ttres()
+          Restores the tty device to the modes and settings that were in
+          effect at the time it was opened (see ttopen). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          ttruncmd(string) char * string;
+          Runs the given command on the local system, but redirects its
+          input and output to the communication (SET LINE, SET PORT, or
+          SET HOST) device. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          ttscarr(carrier) int carrier;
+          Copies its argument to a variable that is global to the other
+          tty-related functions, and then returns it. The values for
+          carrier are defined in ckcdeb.h: CAR_ON, CAR_OFF, CAR_AUTO.
+          ttopen(), ttpkt(), and ttvt() use this variable when deciding
+          how to open the tty device and what modes to select. The
+          meanings are these:
+
+   CAR_OFF: Ignore carrier at all times.
+   CAR_ON: Require carrier at all times, except when dialing. This means,
+   for example, that ttopen() could hang forever waiting for carrier if it
+   is not present.
+   CAR_AUTO: If the modem type is zero (i.e. the connection is direct),
+   this is the same as CAR_OFF. If the modem type is positive, then heed
+   carrier during CONNECT (ttvt mode), but ignore it at other times
+   (packet mode, during SET LINE, etc). Compatible with pre-5A versions of
+   C-Kermit. This should be the default carrier mode.
+
+          Kermit's DIAL command ignores the carrier setting, but ttopen(),
+          ttvt(), and ttpkt() all honor the carrier option in effect at
+          the time they are called. None of this applies to remote mode
+          (the tty device is the job's controlling terminal) or to network
+          host connections (modem type is negative).
+
+   int
+          ttsndb()
+          Sends a BREAK signal on the tty device. On a real tty device,
+          send a real BREAK lasting approximately 275 milliseconds. If
+          this is not possible, simulate a BREAK by (for example) dropping
+          down some very low baud rate, like 50, and sending a bunch of
+          null characters. On a network connection, do the appropriate
+          network protocol for BREAK. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          ttsndlb()
+          Like ttsndb(), but sends a "Long BREAK" (approx 1.5 seconds).
+          For network connections, it is identical to ttsndb(). Currently,
+          this function is used only if CK_LBRK is defined (as it is for
+          UNIX and VMS).
+
+   int
+          ttsspd(cps) int cps;
+          For serial devices only, set the device transmission speed to
+          (note carefully) TEN TIMES the argument. The argument is in
+          characters per second, but transmission speeds are in bits per
+          second. cps are used rather than bps because high speeds like
+          38400 are not expressible in a 16-bit int but longs cannot be
+          used because keyword-table values are ints and not longs. If the
+          argument is 7, then the bps is 75, not 70. If the argument is
+          888, this is a special code for 75/1200 split-speed operation
+          (75 bps out, 1200 bps in). Returns:
+           -1: on error, meaning the requested speed is not valid or
+          available.
+          >=0: on success (don't try to use this value for anything).
+
+   int
+          ttvt(speed,flow) long speed; int flow;
+          Puts the currently open tty device into the appropriate modes
+          for terminal emulation. The arguments are interpreted as in
+          ttpkt(). Side effects: ttvt() stores its arguments in global
+          variables, and sets a flag that it has been called so that
+          subsequent calls can be ignored so long as the arguments are the
+          same as in the last effective call. Other functions, such as
+          ttopen(), ttclose(), ttres(), ttvt(), etc, that change the tty
+          device in any way must unset this flag. In UNIX Kermit, this
+          flag is called tvtflg.
+
+   int
+          ttwmdm(mdmsig,timo) int mdmsig, timo;
+          Waits up to timo seconds for all of the given modem signals to
+          appear. mdmsig is a bit mask, in which a bit is on (1) or off
+          (0) according to whether the corresponding signal is to be
+          waited for. These symbols are defined in ckcdeb.h:
+            BM_CTS (bit 0) means wait for Clear To Send
+            BM_DSR (bit 1) means wait for Data Set Ready
+            BM_DCD (bit 2) means wait for Carrier Detect
+          Returns:
+           -3: Not implemented.
+           -2: This line does not have modem control.
+           -1: Timeout: time limit exceeded before all signals were
+          detected.
+            1: Success.
+
+   int
+          ttxin(n,buf) int n; CHAR *buf;
+          Reads x characters from the tty device into the specified buf,
+          stripping parity if parity is not none. This call waits forever,
+          there is no timeout. This function is designed to be called only
+          when you know that at least x characters are waiting to be read
+          (as determined, for example, by ttchk()). This function should
+          use the same buffer as ttinc().
+
+   int
+          txbufr(timo) int timo;
+          Reads characters into the internal communications input buffer.
+          timo is a timeout interval, in seconds. 0 means no timeout, wait
+          forever. Called by ttinc() (and possibly ttxin() and ttinl())
+          when the communications input buffer is empty. The buffer should
+          be called ttxbuf[], its length is defined by the symbol TXBUFL.
+          The global variable txbufn is the number of characters available
+          to be read from ttxbuf[], and txbufp is the index of the next
+          character to be read. Should not be called if txbufn > 0, in
+          which case the buffer does not need refilling. This routine
+          returns:
+            -2: Communications disconnect
+            -1: Timeout
+          >=0: A character (0 - 255) On success, the first character that
+          was read, with the variables txbufn and txbufp set appropriately
+          for any remaining characters.
+          NOTE: Currently this routine is used internally only by the UNIX
+          and VMS versions. The aim is to make it available to all
+          versions so there is one single coherent and efficient way of
+          reading from the communications device or network.
+
+4.E.2.6. Miscellaneous system-dependent functions
+
+   VOID
+          ztime(s) char **s;
+          Returns a pointer, s, to the current date-and-time string in s.
+          This string must be in the fixed-field format associated with
+          the C runtime asctime() function, like: "Sun Sep 16 13:23:45
+          1973\n" so that callers of this function can extract the
+          different fields. The pointer value is filled in by ztime, and
+          the data it points to is not safe, so should be copied to a safe
+          place before use. ztime() has no return value. As a side effect,
+          this routine can also fill in the following two external
+          variables (which must be defined in the system-dependendent
+          modules for each platform):
+            long ztusec: Fraction of seconds of clock time, microseconds.
+            long ztmsec: Fraction of seconds of clock time, milliseconds.
+          If these variables are not set by zstime(), they remain at their
+          initial value of -1L.
+
+   int
+          gtimer()
+          Returns the current value of the elapsed time counter in seconds
+          (see rtimer), or 0 on any kind of error.
+
+   #ifdef GFTIMER
+          CKFLOAT
+          gftimer()
+          Returns the current value of the elapsed time counter in
+          seconds, as a floating point number, capable of representing not
+          only whole seconds, but also the fractional part, to the
+          millisecond or microsecond level, whatever precision is
+          available. Requires a function to get times at subsecond
+          precision, as well as floating-point support. That's why it's
+          #ifdef'd.
+
+   #endif /* GFTIMER */
+
+   int
+          msleep(m) int m;
+          Sleeps (pauses, does nothing) for m milliseconds (a millisecond
+          is one thousandth of a second). Returns:
+           -1: on failure.
+            0: on success.
+
+   VOID
+          rtimer()
+          Sets the elapsed time counter to zero. If you want to time how
+          long an operation takes, call rtimer() when it starts and gtimer
+          when it ends. rtimer() has no return value.
+
+   #ifdef GFTIMER
+          VOID
+          rftimer()
+          Sets the elapsed time counter to zero. If you want to time how
+          long an operation takes, call rftimer() when it starts and
+          gftimer when it ends. rftimer() has no return value. Note:
+          rftimer() is to be used with gftimer() and rtimer() is to be
+          used with gtimer(). See the rftimer() description.
+
+   #endif /* GFTIMER */
+
+   int
+          sysinit()
+          Does whatever needs doing upon program start. In particular, if
+          the program is running in any kind of privileged mode, turns off
+          the privileges (see priv_ini()). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          syscleanup()
+          Does whatever needs doing upon program exit. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          psuspend()
+          Suspends the Kermit process, puts it in the background so it can
+          be continued ("foregrounded") later. Returns:
+           -1: if this function is not supported.
+            0: on success.
+
+   [ [124]Contents ] [ [125]C-Kermit ] [ [126]Kermit Home ]
+
+4.F. Group F: Network Support
+
+   As of version 5A, C-Kermit includes support for several networks.
+   Originally, this was just worked into the ttopen(), ttclos(), ttinc(),
+   ttinl(), and similar routines in [127]ckutio.c. But this made it
+   impossible to share this code with non-UNIX versions, like VMS, AOS/VS,
+   OS/2, etc. So as of edit 168, network code has been separated out into
+   its own module and header file, ckcnet.c and ckcnet.h:
+
+     [128]ckcnet.h: Network-related symbol definitions.
+     [129]ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most
+   platforms.
+     [130]cklnet.c: Network i/o (TCP/IP, X.25, etc) specific to Stratus
+   VOS.
+
+   The routines and variables in these modules fall into two categories:
+
+    1. Support for specific network packages like SunLink X.25 and TGV
+       MultiNet, and:
+    2. support for specific network virtual terminal protocols like CCITT
+       X.3 and TCP/IP Telnet.
+
+   Category (1) functions are analogs to the tt*() functions, and have
+   names like netopen, netclos, nettinc, etc. Group A-D modules do not
+   (and must not) know anything about these functions -- they continue to
+   call the old Group E functions (ttopen, ttinc, etc). Category (2)
+   functions are protocol specific and have names prefixed by a protocol
+   identifier, like tn for telnet x25 for X.25.
+
+   ckcnet.h contains prototypes for all these functions, as well as symbol
+   definitions for network types, protocols, and network- and protocol-
+   specific symbols, as well as #includes for the header files necessary
+   for each network and protocol.
+
+   The following functions are to be provided for networks that do not use
+   normal system i/o (open, read, write, close):
+
+   int
+          netopen()
+          To be called from within ttopen() when a network connection is
+          requested. Calling conventions and purpose same as Group E
+          ttopen().
+
+   int
+          netclos()
+          To be called from within ttclos() when a network connection is
+          being closed. Calling conventions and purpose same as Group E
+          ttclos().
+
+   int
+          nettchk()
+          To be called from within ttchk(). Calling conventions and
+          purpose same as Group E ttchk().
+
+   int
+          netflui()
+          To be called from within ttflui(). Calling conventions and
+          purpose same as Group E ttflui().
+
+   int
+          netbreak()
+          To send a network break (attention) signal. Calling conventions
+          and purpose same as Group E ttsndbrk().
+
+   int
+          netinc()
+          To get a character from the network. Calling conventions same as
+          Group E ttsndbrk().
+
+   int
+          nettoc()
+          Send a "character" (byte) to the network. Calling conventions
+          same as Group E ttoc().
+
+   int
+          nettol()
+          Send a "line" (sequence of bytes) to the network. Calling
+          conventions same as Group E ttol().
+
+   Conceivably, some systems support network connections simply by letting
+   you open a device of a certain name and letting you do i/o to it.
+   Others (like the Berkeley sockets TCP/IP library on UNIX) require you
+   to open the connection in a special way, but then do normal i/o (read,
+   write). In such a case, you would use netopen(), but you would not use
+   nettinc, nettoc, etc.
+
+   VMS TCP/IP products have their own set of functions for all network
+   operations, so in that case the full range of netxxx() functions is
+   used.
+
+   The technique is to put a test in each corresponding ttxxx() function
+   to see if a network connection is active (or is being requested), test
+   for which kind of network it is, and if necessary route the call to the
+   corresponding netxxx() function. The netxxx() function must also
+   contain code to test for the network type, which is available via the
+   global variable ttnet.
+
+   [ [131]Contents ] [ [132]C-Kermit ] [ [133]Kermit Home ]
+
+4.F.1. Telnet Protocol
+
+   (This section needs a great deal of updating...)
+
+   As of edit 195, Telnet protocol is split out into its own files, since
+   it can be implemented in remote mode, which does not have a network
+   connection:
+
+      [134]ckctel.h: Telnet protocol symbol definitions.
+      [135]ckctel.c: Telnet protocol.
+
+   The Telnet protocol is supported by the following variables and
+   routines:
+
+   int tn_init
+          Nonzero if telnet protocol initialized, zero otherwise.
+
+   int
+          tn_init()
+          Initialize the telnet protocol (send initial options).
+
+   int
+          tn_sopt()
+          Send a telnet option.
+
+   int
+          tn_doop()
+          Receive and act on a telnet option from the remote.
+
+   int
+          tn_sttyp()
+          Send terminal type using telnet protocol.
+
+4.F.2. FTP Protocol
+
+   (To be filled in...)
+
+4.F.3. HTTP Protocol
+
+   (To be filled in...)
+
+4.F.4. X.25 Networks
+
+   These routines were written SunLink X.25 and have since been adapted to
+   at least on one other: IBM AIXLink/X.25.
+
+   int
+          x25diag()
+          Reads and prints X.25 diagnostics
+
+   int
+          x25oobh()
+          X.25 out of band signal handler
+
+   int
+          x25intr()
+          Sends X.25 interrupt packet
+
+   int
+          x25reset()
+          Resets X.25 virtual circuit
+
+   int
+          x25clear()
+          Clear X.25 virtual circuit
+
+   int
+          x25stat()
+          X.25 status
+
+   int
+          setqbit()
+          Sets X.25 Q-bit
+
+   int
+          resetqbit()
+          Resets X.25 Q-bit
+
+   int
+          x25xin()
+          Reads n characters from X.25 circuit.
+
+   int
+          x25inl()
+          Read a Kermit packet from X.25 circuit.
+
+   [ [136]Contents ] [ [137]C-Kermit ] [ [138]Kermit Home ]
+
+4.F.5. Adding New Network Types
+
+   Example: Adding support for IBM X.25 and Hewlett Packard X.25. First,
+   add new network type symbols for each one. There are already some
+   network types defined for other X.25 packages:
+
+  NET_SX25 is the network-type ID for SunLink X.25.
+  NET_VX25 is the network-type ID for VOS X.25.
+
+   So first you should new symbols for the new network types, giving them
+   the next numbers in the sequence, e.g.:
+
+#define NET_HX25 11                     /* Hewlett-Packard X.25 */
+#define NET_IX25 12                     /* IBM X.25 */
+
+   This is in ckcnet.h.
+
+   Then we need symbols to say that we are actually compiling in the code
+   for these platforms. These would be defined on the cc command line:
+
+  -DIBMX25  (for IBM)
+  -DHPX25   (for HP)
+
+   So we can build C-Kermit versions for AIX and HP-UX both with and
+   without X.25 support (since not all AIX and IBM systems have the needed
+   libraries, and so an executable that was linked with them might no
+   load).
+
+   Then in ckcnet.h:
+
+#ifdef IBMX25
+#define ANYX25
+#endif /* IBMX25 */
+
+#ifdef HPX25
+#define ANYX25
+#endif /* HPX25 */
+
+   And then use ANYX25 for code that is common to all of them, and IBMX25
+   or HPX25 for code specific to IBM or HP.
+
+   It might also happen that some code can be shared between two or more
+   of these, but not the others. Suppose, for example, that you write code
+   that applies to both IBM and HP, but not Sun or VOS X.25. Then you add
+   the following definition to ckcnet.h:
+
+#ifndef HPORIBMX25
+#ifdef HPX25
+#define HPORIBMX25
+#else
+#ifdef IBMX25
+#define HPORIBMX25
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* HPORIBMX25 */
+
+   You can NOT use constructions like "#if defined (HPX25 || IBMX25)";
+   they are not portable.
+
+   [ [139]Contents ] [ [140]C-Kermit ] [ [141]Kermit Home ]
+
+4.G. Group G: Formatted Screen Support
+
+   So far, this is used only for the fullscreen local-mode file transfer
+   display. In the future, it might be extended to other uses. The
+   fullscreen display code is in and around the routine screenc() in
+   [142]ckuusx.c.
+
+   In the UNIX version, we use the curses library, plus one call from the
+   termcap library. In other versions (OS/2, VMS, etc) we insert dummy
+   routines that have the same names as curses routines. So far, there are
+   two methods for simulating curses routines:
+
+    1. In VMS, we use the Screen Management Library (SMG), and insert
+       stubs to convert curses calls into SMG calls.
+    2. In OS/2, we use the MYCURSES code, in which the stub routines
+       actually emit the appropriate escape sequences themselves.
+
+   Here are the stub routines:
+
+   int
+          tgetent(char *buf, char *term)
+          Arguments are ignored. Returns 1 if the user has a supported
+          terminal type, 0 otherwise. Sets a global variable (for example,
+          "isvt52" or "isdasher") to indicate the terminal type.
+
+   VOID
+          move(int row, int col)
+          Sends the escape sequence to position the cursor at the
+          indicated row and column. The numbers are 0-based, e.g. the home
+          position is 0,0.
+
+   int
+          clear()
+          Sends the escape sequence to clear the screen.
+
+   int
+          clrtoeol()
+          Sends the escape sequence to clear from the current cursor
+          position to the end of the line.
+
+   In the MYCURSES case, code must be added to each of the last three
+   routines to emit the appropriate escape sequences for a new terminal
+   type.
+
+   clearok(curscr), wrefresh()
+          In real curses, these two calls are required to refresh the
+          screen, for example after it was fractured by a broadcast
+          message. These are useful only if the underlying screen
+          management service keeps a copy of the entire screen, as curses
+          and SMG do. C-Kermit does not do this itself.
+
+   [ [143]Contents ] [ [144]C-Kermit ] [ [145]Kermit Home ]
+
+4.H. Group H: Pseudoterminal Support
+
+   (To be filled in...)
+
+4.I. Group I: Security
+
+   (To be filled in...)
+
+   [ [146]Contents ] [ [147]C-Kermit ] [ [148]Kermit Home ]
+
+APPENDIX I. FILE PERMISSIONS
+
+I.1. Format of System-Dependent File Permissions in A-Packets
+
+   The format of this field (the "," attribute) is interpreted according
+   to the System ID ("." Attribute).
+
+   For UNIX (System ID = U1), it's the familiar 3-digit octal number, the
+   low-order 9 bits of the filemode: Owner, Group, World, e.g. 660 =
+   read/write access for owner and group, none for world, recorded as a
+   3-digit octal string. High-order UNIX permission bits are not
+   transmitted.
+
+   For VMS (System ID = D7), it's a 4-digit hex string, representing the
+   16-bit file protection WGOS fields (World,Group,Owner,System), in that
+   order (which is the reverse of how they're shown in a directory
+   listing); in each field, Bit 0 = Read, 1 = Write, 2 = Execute, 3 =
+   Delete. A bit value of 0 means permission is granted, 1 means
+   permission is denied. Sample:
+
+  r-01-00-^A/!FWERMIT.EXE'"
+  s-01-00-^AE!Y/amd/watsun/w/fdc/new/wermit.exe.DV
+  r-02-01-^A]"A."D7""B8#119980101 18:14:05!#8531&872960,$A20B-!7(#512@ #.Y
+  s-02-01-^A%"Y.5!
+
+   A VMS directory listing shows the file's protection as (E,RWED,RED,RE)
+   which really means (S=E,O=RWED,G=RED,W=RE), which is reverse order from
+   the internal storage, so (RE,RED,RWED,E). Now translate each letter to
+   its corresponding bit:
+
+  RE=0101, RED=1101, RWED=1111, E=0010
+
+   Now reverse the bits:
+
+  RE=1010, RED=0010, RWED=0000, E=1101
+
+   This gives the 16-bit quantity:
+
+  1010001000001101
+
+   This is the internal representation of the VMS file permission; in hex:
+
+  A20B
+
+   as shown in the sample packet above.
+
+   The VMS format probably would also apply to RSX or any other FILES-11
+   system.
+
+I.2. Handling of Generic Protection
+
+   To be used when the two systems are different (and/or do not recognize
+   or understand each other's local protection codes).
+
+   First of all, the book is wrong. This should not be the World
+   protection, but the Owner protection. The other fields should be set
+   according to system defaults (e.g. UNIX umask, VMS default protection,
+   etc), except that no non-Owner field should give more permissions than
+   the Owner field.
+
+   [ [149]Top ] [ [150]Contents ] [ [151]C-Kermit Home ] [ [152]Kermit
+   Home ]
+     __________________________________________________________________
+
+
+    C-Kermit Program Logic Manual / [153]The Kermit Project /
+    [154]kermit@columbia.edu / 30 June 2011
+
+References
+
+   1. http://www.columbia.edu/
+   2. mailto:kermit@columbia.edu
+   3. http://www.columbia.edu/kermit/index.html
+   4. http://www.columbia.edu/kermit/k95.html
+   5. http://www.columbia.edu/kermit/ckermit.html
+   6. http://www.columbia.edu/kermit/ckscripts.html
+   7. http://www.columbia.edu/kermit/current.html
+   8. http://www.columbia.edu/kermit/whatsnew.html
+   9. http://www.columbia.edu/kermit/ckfaq.html
+  10. http://www.columbia.edu/kermit/support.html
+  11. http://www.columbia.edu/kermit/
+  12. http://www.columbia.edu/
+  13. http://www.columbia.edu/kermit/ckcplm.html
+  14. http://www.columbia.edu/kermit/ckermit.html
+  15. http://www.columbia.edu/kermit/index.html
+  16. http://www.columbia.edu/kermit/ckcplm.html#x1
+  17. http://www.columbia.edu/kermit/ckcplm.html#x2
+  18. http://www.columbia.edu/kermit/ckcplm.html#x3
+  19. http://www.columbia.edu/kermit/ckcplm.html#x4
+  20. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+  21. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  22. http://www.columbia.edu/kermit/ckcplm.html#x4.C
+  23. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+  24. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  25. http://www.columbia.edu/kermit/ckcplm.html#x4.F
+  26. http://www.columbia.edu/kermit/ckcplm.html#x4.G
+  27. http://www.columbia.edu/kermit/ckcplm.html#x4.H
+  28. http://www.columbia.edu/kermit/ckcplm.html#x4.I
+  29. http://www.columbia.edu/kermit/ckcplm.html#xa1
+  30. http://www.columbia.edu/kermit/ckcplm.html#contents
+  31. http://www.columbia.edu/kermit/ckcplm.html#contents
+  32. http://www.columbia.edu/kermit/ckermit.html
+  33. http://www.columbia.edu/kermit/index.html
+  34. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+  35. http://www.columbia.edu/kermit/ckcplm.html#contents
+  36. http://www.columbia.edu/kermit/ckermit.html
+  37. http://www.columbia.edu/kermit/index.html
+  38. http://www.columbia.edu/kermit/ckcplm.html#x3.2
+  39. http://www.columbia.edu/kermit/ckcplm.html#contents
+  40. http://www.columbia.edu/kermit/ckermit.html
+  41. http://www.columbia.edu/kermit/index.html
+  42. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+  43. http://www.columbia.edu/kermit/ckcplm.html#contents
+  44. http://www.columbia.edu/kermit/ckermit.html
+  45. http://www.columbia.edu/kermit/index.html
+  46. http://www.columbia.edu/kermit/ckcplm.html#contents
+  47. http://www.columbia.edu/kermit/ckermit.html
+  48. http://www.columbia.edu/kermit/index.html
+  49. http://www.columbia.edu/kermit/ckcplm.html#contents
+  50. http://www.columbia.edu/kermit/ckermit.html
+  51. http://www.columbia.edu/kermit/index.html
+  52. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.h
+  53. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.c
+  54. http://www.columbia.edu/kermit/ckcplm.html#x3.1
+  55. http://www.columbia.edu/kermit/ckcplm.html#contents
+  56. http://www.columbia.edu/kermit/ckermit.html
+  57. http://www.columbia.edu/kermit/index.html
+  58. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsym.h
+  59. ftp://kermit.columbia.edu/kermit/c-kermit/ckcasc.h
+  60. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsig.h
+  61. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+  62. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
+  63. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+  64. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+  65. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+  66. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfns.c
+  67. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn2.c
+  68. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn3.c
+  69. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  70. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  71. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+  72. http://www.columbia.edu/kermit/ckcplm.html#contents
+  73. http://www.columbia.edu/kermit/ckermit.html
+  74. http://www.columbia.edu/kermit/index.html
+  75. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  76. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.c
+  77. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+  78. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+  79. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+  80. ftp://kermit.columbia.edu/kermit/c-kermit/ckmxla.h
+  81. ftp://kermit.columbia.edu/kermit/c-kermit/ck?xla
+  82. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.h
+  83. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
+  84. http://www.columbia.edu/kermit/ckcplm.html#contents
+  85. http://www.columbia.edu/kermit/ckermit.html
+  86. http://www.columbia.edu/kermit/index.html
+  87. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  88. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.h
+  89. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
+  90. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  91. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+  92. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.c
+  93. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus2.c
+  94. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+  95. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus4.c
+  96. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusy.c
+  97. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+  98. ftp://kermit.columbia.edu/kermit/c-kermit/ckuver.h
+  99. ftp://kermit.columbia.edu/kermit/c-kermit/ckuscr.c
+ 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
+ 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
+ 102. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
+ 103. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+ 104. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 105. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 106. http://www.columbia.edu/kermit/ckermit.html
+ 107. http://www.columbia.edu/kermit/index.html
+ 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 109. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 110. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 111. ftp://kermit.columbia.edu/kermit/c-kermit/ckvfio.c
+ 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 114. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 115. http://www.columbia.edu/kermit/ckermit.html
+ 116. http://www.columbia.edu/kermit/index.html
+ 117. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 118. ftp://kermit.columbia.edu/kermit/c-kermit/ckvtio.c
+ 119. http://www.columbia.edu/kermit/ckcplm.html#x2
+ 120. http://www.columbia.edu/kermit/ckcplm.html#xa1
+ 121. http://www.columbia.edu/kermit/ckuins.html
+ 122. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 123. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 124. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 125. http://www.columbia.edu/kermit/ckermit.html
+ 126. http://www.columbia.edu/kermit/index.html
+ 127. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 128. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 129. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 130. ftp://kermit.columbia.edu/kermit/c-kermit/cklnet.c
+ 131. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 132. http://www.columbia.edu/kermit/ckermit.html
+ 133. http://www.columbia.edu/kermit/index.html
+ 134. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
+ 135. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 136. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 137. http://www.columbia.edu/kermit/ckermit.html
+ 138. http://www.columbia.edu/kermit/index.html
+ 139. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 140. http://www.columbia.edu/kermit/ckermit.html
+ 141. http://www.columbia.edu/kermit/index.html
+ 142. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 143. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 144. http://www.columbia.edu/kermit/ckermit.html
+ 145. http://www.columbia.edu/kermit/index.html
+ 146. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 147. http://www.columbia.edu/kermit/ckermit.html
+ 148. http://www.columbia.edu/kermit/index.html
+ 149. http://www.columbia.edu/kermit/ckcplm.html#top
+ 150. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 151. http://www.columbia.edu/kermit/ckermit.html
+ 152. http://www.columbia.edu/kermit/index.html
+ 153. http://www.columbia.edu/kermit/index.html
+ 154. mailto:kermit@columbia.edu