--- /dev/null
+
+ [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