| |
| C-Kermit Program Logic Manual |
| |
| Frank da Cruz |
| [1]The Kermit Project |
| [2]Columbia University |
| |
| As of: C-Kermit 8.0.211, 10 April 2004 |
| This page last updated: Sat Apr 10 16:45:30 2004 (New York USA Time) |
| |
| 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: |
| |
| [3]http://www.columbia.edu/kermit/ckcplm.html |
| |
| [ [4]C-Kermit Home ] [ [5]Kermit Home ] |
| ________________________________________________________________________ |
| |
| CONTENTS |
| |
| 1. [6]INTRODUCTION |
| 2. [7]FILES |
| 3. [8]SOURCE CODE PORTABILITY AND STYLE |
| 4. [9]MODULES |
| 4.A. [10]Group A: Library Routines |
| 4.B. [11]Group B: Kermit File Transfer |
| 4.C. [12]Group C: Character-Set Conversion |
| 4.D. [13]Group D: User Interface |
| 4.E. [14]Group E: Platform-Dependent I/O |
| 4.F. [15]Group F: Network Support |
| 4.G. [16]Group G: Formatted Screen Support |
| 4.H. [17]Group H: Pseudoterminal Support |
| 4.I. [18]Group I: Security |
| I. [19]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 [20]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. |
| |
| [ [21]Contents ] [ [22]C-Kermit ] [ [23]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 [24]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). |
| |
| [ [25]Contents ] [ [26]C-Kermit ] [ [27]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 [28]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. |
| |
| [ [29]Contents ] [ [30]C-Kermit ] [ [31]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 [32]Section 4.A. |
| |
| [ [33]Contents ] [ [34]C-Kermit ] [ [35]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. |
| |
| [ [36]Contents ] [ [37]C-Kermit ] [ [38]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). |
| |
| [ [39]Contents ] [ [40]C-Kermit ] [ [41]Kermit Home ] |
| ________________________________________________________________________ |
| |
| 4.A. Group A: Library Functions |
| |
| Library functions, strictly portable, can be used by all modules on |
| all platforms: [42]ckclib.h, [43]ckclib.c. |
| |
| (To be filled in... For now, see [44]Section 3.1 and the comments in |
| ckclib.c.) |
| |
| [ [45]Contents ] [ [46]C-Kermit ] [ [47]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: |
| |
| [48]ckcsym.h |
| For use by C compilers that don't allow -D on the command line. |
| |
| [49]ckcasc.h |
| ASCII character symbol definitions. |
| |
| [50]ckcsig.h |
| System-independent signal-handling definitions and prototypes. |
| |
| [51]ckcdeb.h |
| Originally, debugging definitions. Now this file also contains |
| all definitions and prototypes that are shared by all modules |
| in all groups. |
| |
| [52]ckcker.h |
| Kermit protocol symbol definitions. |
| |
| [53]ckcxla.h |
| Character-set-related symbol definitions (see next section). |
| |
| [54]ckcmai.c |
| The main program. This module contains the declarations of all |
| the protocol-related global variables that are shared among the |
| other modules. |
| |
| [55]ckcpro.w |
| The protocol module itself, written in "wart", a lex-like |
| preprocessor that is distributed with Kermit under the name |
| CKWART.C. |
| |
| [56]ckcfns.c, [57]ckcfn2.c, [58]ckcfn3.c |
| The protocol support functions used by the protocol module. |
| |
| [59]Group B modules may call upon functions from [60]Group E, but not |
| from [61]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.) |
| |
| [ [62]Contents ] [ [63]C-Kermit ] [ [64]Kermit Home ] |
| ________________________________________________________________________ |
| |
| 4.C. Group C: Character-Set Conversion |
| |
| Character set translation tables and functions. Used by the [65]Group |
| B, protocol modules, but may be specific to different computers. (So |
| far, all character character sets supported by C-Kermit are supported |
| in [66]ckuxla.c and [67]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. |
| |
| [68]ckcxla.h |
| Character-set definitions usable by all versions of C-Kermit. |
| |
| ck?xla.h |
| Character-set definitions for computer "?", e.g. [69]ckuxla.h |
| for UNIX, [70]ckmxla.h for Macintosh. |
| |
| [71]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. |
| |
| [72]ckcuni.h |
| Unicode definitions |
| |
| [73]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...) |
| |
| [ [74]Contents ] [ [75]C-Kermit ] [ [76]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 [77]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). |
| |
| [78]ckucmd.h |
| [79]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 [80]Group E functions. |
| |
| [81]ckuusr.h |
| Definitions of symbols used in Kermit's commands. |
| |
| ckuus*.c |
| Kermit's interactive command parser, including the script |
| programming language: [82]ckuusr.c (includes top-level keyword |
| tables); [83]ckuus2.c (HELP command text); [84]ckuus3.c (most |
| of the SET command); [85]ckuus4.c (includes variables and |
| functions); ckuus[567].c (miscellaneous); |
| |
| [86]ckuusy.c |
| The command-line-option parser. |
| |
| [87]ckuusx.c |
| User interface functions common to both the interactive and |
| command-line parsers. |
| |
| [88]ckuver.h |
| Version heralds for different implementations. |
| |
| [89]ckuscr.c |
| The (old, uucp-like) SCRIPT command |
| |
| [90]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: |
| [91]ckucon.c -- the traditional, portable, fork()-based version |
| -- and [92]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 [93]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 [94]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. |
| |
| [ [95]Contents ] [ [96]C-Kermit ] [ [97]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 [98]ckufio.c (files), [99]ckutio.c (communications), and |
| [100]ckusig.c (signal handling). |
| |
| For VMS, the files are [101]ckvfio.c, ckvtio.c, and [102]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 [103]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. |
| |
| [ [104]Contents ] [ [105]C-Kermit ] [ [106]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" ([107]ckutio.c for Unix), "v" |
| ([108]ckvtio.c for VMS), [109]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 |
| [110]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 [111]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 [112]ckcnet.h: |
| |
| NET_TCPB 1 TCP/IP Berkeley (socket) (implemented in [113]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. |
| |
| [ [114]Contents ] [ [115]C-Kermit ] [ [116]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 [117]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: |
| |
| [118]ckcnet.h: Network-related symbol definitions. |
| [119]ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most |
| platforms. |
| [120]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. |
| |
| [ [121]Contents ] [ [122]C-Kermit ] [ [123]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: |
| |
| [124]ckctel.h: Telnet protocol symbol definitions. |
| [125]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. |
| |
| [ [126]Contents ] [ [127]C-Kermit ] [ [128]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. |
| |
| [ [129]Contents ] [ [130]C-Kermit ] [ [131]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 |
| [132]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. |
| |
| [ [133]Contents ] [ [134]C-Kermit ] [ [135]Kermit Home ] |
| ________________________________________________________________________ |
| |
| 4.H. Group H: Pseudoterminal Support |
| |
| (To be filled in...) |
| ________________________________________________________________________ |
| |
| 4.I. Group I: Security |
| |
| (To be filled in...) |
| |
| [ [136]Contents ] [ [137]C-Kermit ] [ [138]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. |
| |
| [ [139]Top ] [ [140]Contents ] [ [141]C-Kermit Home ] [ [142]Kermit |
| Home ] |
| _________________________________________________________________ |
| |
| |
| C-Kermit Program Logic Manual / [143]The Kermit Project / |
| [144]Columbia University / [145]kermit@columbia.edu / 10 April 2004 |
| |
| References |
| |
| 1. http://www.columbia.edu/kermit/ |
| 2. http://www.columbia.edu/ |
| 3. http://www.columbia.edu/kermit/ckcplm.html |
| 4. http://www.columbia.edu/kermit/ckermit.html |
| 5. http://www.columbia.edu/kermit/index.html |
| 6. http://www.columbia.edu/kermit/ckcplm.html#x1 |
| 7. http://www.columbia.edu/kermit/ckcplm.html#x2 |
| 8. http://www.columbia.edu/kermit/ckcplm.html#x3 |
| 9. http://www.columbia.edu/kermit/ckcplm.html#x4 |
| 10. http://www.columbia.edu/kermit/ckcplm.html#x4.A |
| 11. http://www.columbia.edu/kermit/ckcplm.html#x4.B |
| 12. http://www.columbia.edu/kermit/ckcplm.html#x4.C |
| 13. http://www.columbia.edu/kermit/ckcplm.html#x4.D |
| 14. http://www.columbia.edu/kermit/ckcplm.html#x4.E |
| 15. http://www.columbia.edu/kermit/ckcplm.html#x4.F |
| 16. http://www.columbia.edu/kermit/ckcplm.html#x4.G |
| 17. http://www.columbia.edu/kermit/ckcplm.html#x4.H |
| 18. http://www.columbia.edu/kermit/ckcplm.html#x4.I |
| 19. http://www.columbia.edu/kermit/ckcplm.html#xa1 |
| 20. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 21. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 22. http://www.columbia.edu/kermit/ckermit.html |
| 23. http://www.columbia.edu/kermit/index.html |
| 24. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w |
| 25. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 26. http://www.columbia.edu/kermit/ckermit.html |
| 27. http://www.columbia.edu/kermit/index.html |
| 28. http://www.columbia.edu/kermit/ckcplm.html#x3.2 |
| 29. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 30. http://www.columbia.edu/kermit/ckermit.html |
| 31. http://www.columbia.edu/kermit/index.html |
| 32. http://www.columbia.edu/kermit/ckcplm.html#x4.A |
| 33. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 34. http://www.columbia.edu/kermit/ckermit.html |
| 35. http://www.columbia.edu/kermit/index.html |
| 36. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 37. http://www.columbia.edu/kermit/ckermit.html |
| 38. http://www.columbia.edu/kermit/index.html |
| 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. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.h |
| 43. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.c |
| 44. http://www.columbia.edu/kermit/ckcplm.html#x3.1 |
| 45. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 46. http://www.columbia.edu/kermit/ckermit.html |
| 47. http://www.columbia.edu/kermit/index.html |
| 48. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsym.h |
| 49. ftp://kermit.columbia.edu/kermit/c-kermit/ckcasc.h |
| 50. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsig.h |
| 51. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h |
| 52. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h |
| 53. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h |
| 54. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c |
| 55. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w |
| 56. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfns.c |
| 57. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn2.c |
| 58. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn3.c |
| 59. http://www.columbia.edu/kermit/ckcplm.html#x4.B |
| 60. http://www.columbia.edu/kermit/ckcplm.html#x4.E |
| 61. http://www.columbia.edu/kermit/ckcplm.html#x4.D |
| 62. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 63. http://www.columbia.edu/kermit/ckermit.html |
| 64. http://www.columbia.edu/kermit/index.html |
| 65. http://www.columbia.edu/kermit/ckcplm.html#x4.B |
| 66. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.c |
| 67. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h |
| 68. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h |
| 69. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h |
| 70. ftp://kermit.columbia.edu/kermit/c-kermit/ckmxla.h |
| 71. ftp://kermit.columbia.edu/kermit/c-kermit/ck?xla |
| 72. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.h |
| 73. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c |
| 74. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 75. http://www.columbia.edu/kermit/ckermit.html |
| 76. http://www.columbia.edu/kermit/index.html |
| 77. http://www.columbia.edu/kermit/ckcplm.html#x4.B |
| 78. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.h |
| 79. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c |
| 80. http://www.columbia.edu/kermit/ckcplm.html#x4.E |
| 81. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h |
| 82. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.c |
| 83. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus2.c |
| 84. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c |
| 85. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus4.c |
| 86. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusy.c |
| 87. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c |
| 88. ftp://kermit.columbia.edu/kermit/c-kermit/ckuver.h |
| 89. ftp://kermit.columbia.edu/kermit/c-kermit/ckuscr.c |
| 90. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c |
| 91. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c |
| 92. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c |
| 93. http://www.columbia.edu/kermit/ckcplm.html#x4.E |
| 94. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c |
| 95. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 96. http://www.columbia.edu/kermit/ckermit.html |
| 97. http://www.columbia.edu/kermit/index.html |
| 98. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c |
| 99. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c |
| 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c |
| 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckvfio.c |
| 102. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c |
| 103. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c |
| 104. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 105. http://www.columbia.edu/kermit/ckermit.html |
| 106. http://www.columbia.edu/kermit/index.html |
| 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c |
| 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckvtio.c |
| 109. http://www.columbia.edu/kermit/ckcplm.html#x2 |
| 110. http://www.columbia.edu/kermit/ckcplm.html#xa1 |
| 111. http://www.columbia.edu/kermit/ckuins.html |
| 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h |
| 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.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/ckcnet.h |
| 119. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c |
| 120. ftp://kermit.columbia.edu/kermit/c-kermit/cklnet.c |
| 121. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 122. http://www.columbia.edu/kermit/ckermit.html |
| 123. http://www.columbia.edu/kermit/index.html |
| 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h |
| 125. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c |
| 126. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 127. http://www.columbia.edu/kermit/ckermit.html |
| 128. http://www.columbia.edu/kermit/index.html |
| 129. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 130. http://www.columbia.edu/kermit/ckermit.html |
| 131. http://www.columbia.edu/kermit/index.html |
| 132. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c |
| 133. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 134. http://www.columbia.edu/kermit/ckermit.html |
| 135. http://www.columbia.edu/kermit/index.html |
| 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#top |
| 140. http://www.columbia.edu/kermit/ckcplm.html#contents |
| 141. http://www.columbia.edu/kermit/ckermit.html |
| 142. http://www.columbia.edu/kermit/index.html |
| 143. http://www.columbia.edu/kermit/index.html |
| 144. http://www.columbia.edu/ |
| 145. mailto:kermit@columbia.edu |