123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907 |
- The Kermit Project
- Columbia University
- 612 West 115th Street
- New York NY 10025 USA
- kermit@columbia.edu
- ...since 1981
- C-Kermit Program Logic Manual
- Frank da Cruz
- The Kermit Project
- As of: C-Kermit 9.0.300, 30 June 2011
- Last update: Fri Jul 1 15:47:34 2011
- IF YOU ARE READING A PLAIN-TEXT version of this document, note that
- this file is a plain-text dump of a Web page. You can visit the
- original (and possibly more up-to-date) Web page here:
- http://www.columbia.edu/kermit/ckcplm.html
- CONTENTS
- 1. INTRODUCTION
- 2. FILES
- 3. SOURCE CODE PORTABILITY AND STYLE
- 4. MODULES
- 4.A. Group A: Library Routines
- 4.B. Group B: Kermit File Transfer
- 4.C. Group C: Character-Set Conversion
- 4.D. Group D: User Interface
- 4.E. Group E: Platform-Dependent I/O
- 4.F. Group F: Network Support
- 4.G. Group G: Formatted Screen Support
- 4.H. Group H: Pseudoterminal Support
- 4.I. Group I: Security
- I. 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 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 or communication methods.
- 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" with
- which to "comply".
- Upon first glance at the source code, you will probably be appalled.
- Many will be tempted to clean it up and modernize it. But as soon as
- you do, you are sure to break something. Remember that above all else,
- the C-Kermit code is portable to every Unix platform that ever existed,
- going back Unix V7 (1979)*, and to several other completely different
- and unrelated operating-system families such as DEC/HP VMS, DG AOS/VS,
- and Stratus VOS, as well as to some Unix offshoots like OS-9 and Plan 9
- (from Outer Space). Every release of Kermit has been checked on every
- platform available -- the older the better! -- to make sure it still
- builds and runs. Even today (2011), there are modern Unix systems that
- have non-ANSI C compilers, foremost among them HP-UX (where an ANSI
- optimizing C compiler is available, but only as an expensive add-on).
- In a way, portability is the most important feature of C-Kermit and
- every effort should be made to preserve it through future releases.
- Voluminous edit histories are available going back to May 1985. The
- first versions of C-Kermit were done on our DEC VAX-11/750 with
- Ultrix 1.0 and 2.0 (as well as departmental 750s with 4.2BSD**), DEC
- Pro-380 workstations (desktop PDP-11s) running 2.9BSD, which was
- ported to the 380 by us. Later (1988 or so) on a big VAX 8650 with
- Ultrix, which became an 8700 (these no doubt weighed several tons), and
- finally a succession of non-DEC equipment: an Encore Multimax, 25 years
- worth of Suns, and now Linux on HP Blades. We also had our own VMS
- development systems for some years. All this plus a generous assortment
- of departmental and offsite guest accounts on a multitude of platforms.
- Anyway, the edit histories:
- ckc04e.txt C-Kermit 4.2(030) May 1985 to 4E(072) Jan 1989.
- ckc04f.txt C-Kermit 4F(077) Arp 1989 to 4F(095) Aug 1989.
- ckc168.txt Updates to C-Kermit 5A(168) for VMS Nov 1991
- ckc178.txt C-Kermit 5A(100) Jul 1989 to 5A(178) Jan 1992
- ckc188.txt C-Kermit 5A(188) development, 1992
- ckc189.txt C-Kermit 5A(189) development, 1993
- ckc192.txt C-Kermit 6.0(192) development, 1998
- ckc197.txt C-Kermit 7.0(197) development, 2000
- ckc200.txt C-Kermit 8.0.200 development, 2001
- ckc211.txt C-Kermit 8.0.201 through 8.0.209 2001-2004
- ckc300.txt C-Kermit 9.0.300 June 2011
- _________________________________
- * C-Kermit 6.0 was the last one to be built on V7, as I recall. The
- code should still be good for V7 but it probably has outgrown the
- 16-bit address space. In any case there is still a V7 makefile target
- and a V7 path through the forest of #ifdefs in the code if anybody is
- running V7 on an emulator and would like to try building C-Kermit.
- There is no support for V6 but that is only because no V6 system was
- ever found for development. Notice that some other 16-bit Unixes are
- supported in the code, including 2.9BSD and Tandy Xenix 3.0, but have
- not been tried since C-Kermit 6.0
- ** C-Kermit 9.0.300 was built successfully on 4.2BSD about 25 years
- later, in June 2011.
- 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 (unused)
- o OS/2 and Microsoft Windows 9x/ME/NT/2000/XP/Vista/etc
- p Plan 9 from Bell Labs
- q (reserved)
- r DEC PDP-11 with RSTS/E (never used, open for reassignment)
- s Atari ST GEMDOS (last supported in version 5A(189))
- t DEC PDP-11 with RT-11 (never used, open for reassignment)
- 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
- _ (underscore) 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 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).
- 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-independent 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)...
- * 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 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. Especially 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:
- 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.
- 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 Section 4.A.
- 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.
- 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 communications 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).
- 4.A. Group A: Library Functions
- Library functions, strictly portable, can be used by all modules on all
- platforms: ckclib.h, ckclib.c.
- (To be filled in... For now, see Section 3.1 and the comments in
- ckclib.c.)
- 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:
- ckcsym.h
- For use by C compilers that don't allow -D on the command line.
- ckcasc.h
- ASCII character symbol definitions.
- ckcsig.h
- System-independent signal-handling definitions and prototypes.
- ckcdeb.h
- Originally, debugging definitions. Now this file also contains
- all definitions and prototypes that are shared by all modules in
- all groups.
- ckcker.h
- Kermit protocol symbol definitions.
- ckcxla.h
- Character-set-related symbol definitions (see next section).
- ckcmai.c
- The main program. This module contains the declarations of all
- the protocol-related global variables that are shared among the
- other modules.
- ckcpro.w
- The protocol module itself, written in "wart", a lex-like
- preprocessor that is distributed with Kermit under the name
- CKWART.C.
- ckcfns.c, ckcfn2.c, ckcfn3.c
- The protocol support functions used by the protocol module.
- Group B modules may call upon functions from Group E, but not
- from 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.)
- 4.C. Group C: Character-Set Conversion
- Character set translation tables and functions. Used by the Group
- B, protocol modules, but may be specific to different computers. (So
- far, all character character sets supported by C-Kermit are supported
- in ckuxla.c and 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.
- ckcxla.h
- Character-set definitions usable by all versions of C-Kermit.
- ck?xla.h
- Character-set definitions for computer "?", e.g. ckuxla.h
- for UNIX, ckmxla.h for Macintosh.
- 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.
- ckcuni.h
- Unicode definitions
- 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...)
- 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 embed the 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).
- ckucmd.h
- 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 Group E functions.
- ckuusr.h
- Definitions of symbols used in Kermit's commands.
- ckuus*.c
- Kermit's interactive command parser, including the script
- programming language: ckuusr.c (includes top-level keyword
- tables); ckuus2.c (HELP command text); ckuus3.c (most
- of the SET command); ckuus4.c (includes variables and
- functions); ckuus.c (miscellaneous);
- ckuusy.c
- The command-line-option parser.
- ckuusx.c
- User interface functions common to both the interactive and
- command-line parsers.
- ckuver.h
- Version heralds for different implementations.
- ckuscr.c
- The (old, uucp-like) SCRIPT command
- 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:
- ckucon.c -- the traditional, portable, fork()-based version
- -- and 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 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 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.
- 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 ckufio.c (files), ckutio.c (communications), and
- ckusig.c (signal handling).
- For VMS, the files are ckvfio.c, ckvtio.c, and 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 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 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.
- 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" (ckutio.c for Unix), "v"
- (ckvtio.c for VMS), 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 /* Auxiliary 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 argument 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
- 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 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 canceled 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 ckcnet.h:
- NET_TCPB 1 TCP/IP Berkeley (socket) (implemented in 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-dependent 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.
- 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 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:
- ckcnet.h: Network-related symbol definitions.
- ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most
- platforms.
- 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.
- 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:
- ckctel.h: Telnet protocol symbol definitions.
- 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...) See the source file
- 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.
- 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.
- 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
- 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.
- 4.H. Group H: Pseudoterminal Support
- (To be filled in...) But see: these comments, and the source files
- ckupty.h and ckupty.c.
- 4.I. Group I: Security
- (To be filled in...) Meanwhile, see security.html.
- 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.
- __________________________________________________________________
- C-Kermit Program Logic Manual
- The Kermit Project
- kermit@columbia.edu
- 30 June 2011
|